From b1dea93f0bbe01d77b1cc140823cc71f55896683 Mon Sep 17 00:00:00 2001 From: Thibault Vallin Date: Tue, 30 Jul 2024 09:11:46 +0200 Subject: [PATCH 01/37] 4.x: native-image - Add required reflection configuration for EclipseLink (#8871) * Add required EclipsLink reflection for native image Signed-off-by: tvallin --- .../native-image.properties | 17 ++++++ .../reflect-config.json | 53 +++++++++++++++++++ .../resource-config.json | 21 ++++++++ 3 files changed, 91 insertions(+) create mode 100644 integrations/cdi/eclipselink-cdi/src/main/resources/META-INF/native-image/io/helidon/integrations/cdi/helidon-integrations-cdi-eclipselink/native-image.properties create mode 100644 integrations/cdi/eclipselink-cdi/src/main/resources/META-INF/native-image/io/helidon/integrations/cdi/helidon-integrations-cdi-eclipselink/reflect-config.json create mode 100644 integrations/cdi/eclipselink-cdi/src/main/resources/META-INF/native-image/org/eclipse/persistence/org.eclipse.persistence.core/resource-config.json diff --git a/integrations/cdi/eclipselink-cdi/src/main/resources/META-INF/native-image/io/helidon/integrations/cdi/helidon-integrations-cdi-eclipselink/native-image.properties b/integrations/cdi/eclipselink-cdi/src/main/resources/META-INF/native-image/io/helidon/integrations/cdi/helidon-integrations-cdi-eclipselink/native-image.properties new file mode 100644 index 00000000000..ae0e3c8bd25 --- /dev/null +++ b/integrations/cdi/eclipselink-cdi/src/main/resources/META-INF/native-image/io/helidon/integrations/cdi/helidon-integrations-cdi-eclipselink/native-image.properties @@ -0,0 +1,17 @@ +# +# Copyright (c) 2024 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. +# + +Args=--initialize-at-build-time=org.eclipse.persistence diff --git a/integrations/cdi/eclipselink-cdi/src/main/resources/META-INF/native-image/io/helidon/integrations/cdi/helidon-integrations-cdi-eclipselink/reflect-config.json b/integrations/cdi/eclipselink-cdi/src/main/resources/META-INF/native-image/io/helidon/integrations/cdi/helidon-integrations-cdi-eclipselink/reflect-config.json new file mode 100644 index 00000000000..efc118d5325 --- /dev/null +++ b/integrations/cdi/eclipselink-cdi/src/main/resources/META-INF/native-image/io/helidon/integrations/cdi/helidon-integrations-cdi-eclipselink/reflect-config.json @@ -0,0 +1,53 @@ +[ + { + "name": "io.helidon.integrations.cdi.eclipselink.CDISEPlatform", + "methods": [ + { + "name": "", + "parameterTypes": [ + "org.eclipse.persistence.sessions.DatabaseSession" + ] + } + ] + }, + { + "name": "io.helidon.integrations.cdi.eclipselink.CDISEPlatform$TransactionController", + "methods": [ + { + "name": "" + } + ] + }, + { + "name": "org.eclipse.persistence.logging.JavaLog", + "methods": [ + { + "name": "" + } + ] + }, + { + "name": "org.eclipse.persistence.platform.database.H2Platform", + "methods": [ + { + "name": "" + } + ] + }, + { + "name": "org.eclipse.persistence.platform.database.MySQLPlatform", + "methods": [ + { + "name": "" + } + ] + }, + { + "name": "org.eclipse.persistence.platform.database.PostgreSQLPlatform", + "methods": [ + { + "name": "" + } + ] + } +] diff --git a/integrations/cdi/eclipselink-cdi/src/main/resources/META-INF/native-image/org/eclipse/persistence/org.eclipse.persistence.core/resource-config.json b/integrations/cdi/eclipselink-cdi/src/main/resources/META-INF/native-image/org/eclipse/persistence/org.eclipse.persistence.core/resource-config.json new file mode 100644 index 00000000000..3edd34f97cc --- /dev/null +++ b/integrations/cdi/eclipselink-cdi/src/main/resources/META-INF/native-image/org/eclipse/persistence/org.eclipse.persistence.core/resource-config.json @@ -0,0 +1,21 @@ +{ + "bundles": [ + { + "name": "org.eclipse.persistence.exceptions.i18n.EntityManagerSetupExceptionResource" + }, + { + "name": "org.eclipse.persistence.exceptions.i18n.ValidationExceptionResource" + }, + { + "name": "org.eclipse.persistence.internal.localization.i18n.EclipseLinkLocalizationResource" + }, + { + "name": "org.eclipse.persistence.internal.localization.i18n.LoggingLocalizationResource" + } + ], + "resources": [ + { + "pattern": ".*version.properties" + } + ] +} From ba179fdd5a1de16b6154924487650ec05626c263 Mon Sep 17 00:00:00 2001 From: Andrei Arlou Date: Tue, 30 Jul 2024 15:07:44 +0300 Subject: [PATCH 02/37] 4.x: Replace deprecated method Span.baggage(key) on Span.baggage().get(key) (#9042) --- .../helidon/tracing/providers/jaeger/JaegerBaggageTest.java | 2 +- .../tracing/providers/opentelemetry/OpenTelemetrySpan.java | 2 +- .../tracing/providers/opentelemetry/TestBaggageApi.java | 2 +- .../tracing/providers/opentelemetry/TestSpanAndBaggage.java | 6 +++--- .../tracing/providers/opentracing/OpenTracingSpan.java | 2 +- .../tracing/providers/opentracing/TestBaggageApi.java | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tracing/providers/jaeger/src/test/java/io/helidon/tracing/providers/jaeger/JaegerBaggageTest.java b/tracing/providers/jaeger/src/test/java/io/helidon/tracing/providers/jaeger/JaegerBaggageTest.java index 3fb1add46e2..84e06e90a61 100644 --- a/tracing/providers/jaeger/src/test/java/io/helidon/tracing/providers/jaeger/JaegerBaggageTest.java +++ b/tracing/providers/jaeger/src/test/java/io/helidon/tracing/providers/jaeger/JaegerBaggageTest.java @@ -40,7 +40,7 @@ class JaegerBaggageTest { void testBaggage(){ Span span = tracer.spanBuilder("test-span").start(); Span spanWithBaggage = span.baggage("key", "value"); - Optional result = spanWithBaggage.baggage("key"); + Optional result = spanWithBaggage.baggage().get("key"); assertThat(result.isPresent(), is(true)); assertThat(result.get(), equalTo("value")); diff --git a/tracing/providers/opentelemetry/src/main/java/io/helidon/tracing/providers/opentelemetry/OpenTelemetrySpan.java b/tracing/providers/opentelemetry/src/main/java/io/helidon/tracing/providers/opentelemetry/OpenTelemetrySpan.java index 7f2c1b5a8d5..6aea08718b6 100644 --- a/tracing/providers/opentelemetry/src/main/java/io/helidon/tracing/providers/opentelemetry/OpenTelemetrySpan.java +++ b/tracing/providers/opentelemetry/src/main/java/io/helidon/tracing/providers/opentelemetry/OpenTelemetrySpan.java @@ -281,7 +281,7 @@ public Span baggage(String key, String value) { @Override public Optional baggage(String key) { - return delegate.baggage(key); + return delegate.baggage().get(key); } @Override diff --git a/tracing/providers/opentelemetry/src/test/java/io/helidon/tracing/providers/opentelemetry/TestBaggageApi.java b/tracing/providers/opentelemetry/src/test/java/io/helidon/tracing/providers/opentelemetry/TestBaggageApi.java index f147c6e6890..c0f2dca8401 100644 --- a/tracing/providers/opentelemetry/src/test/java/io/helidon/tracing/providers/opentelemetry/TestBaggageApi.java +++ b/tracing/providers/opentelemetry/src/test/java/io/helidon/tracing/providers/opentelemetry/TestBaggageApi.java @@ -49,7 +49,7 @@ void testWritableBaggageFromSpan() { baggage.set("keyB", "valB"); assertThat("Assigned baggage via baggage API value from span", - span.baggage("keyB"), + span.baggage().get("keyB"), OptionalMatcher.optionalValue(is(equalTo("valB")))); assertThat("Assigned via baggage API value is present", baggage.containsKey("keyB"), is(true)); assertThat("Assigned via baggage API value from baggage API", diff --git a/tracing/providers/opentelemetry/src/test/java/io/helidon/tracing/providers/opentelemetry/TestSpanAndBaggage.java b/tracing/providers/opentelemetry/src/test/java/io/helidon/tracing/providers/opentelemetry/TestSpanAndBaggage.java index fb91d3292c2..4bedddf49b8 100644 --- a/tracing/providers/opentelemetry/src/test/java/io/helidon/tracing/providers/opentelemetry/TestSpanAndBaggage.java +++ b/tracing/providers/opentelemetry/src/test/java/io/helidon/tracing/providers/opentelemetry/TestSpanAndBaggage.java @@ -104,8 +104,8 @@ void testIncomingBaggage() { assertThat("Span context from inbound headers", spanContextOpt, OptionalMatcher.optionalPresent()); Span span = tracer.spanBuilder("inbound").parent(spanContextOpt.get()).start(); span.end(); - assertThat("Inbound baggage bag1", span.baggage("bag1"), OptionalMatcher.optionalValue(is("val1"))); - assertThat("Inbound baggage bag1", span.baggage("bag2"), OptionalMatcher.optionalValue(is("val2"))); + assertThat("Inbound baggage bag1", span.baggage().get("bag1"), OptionalMatcher.optionalValue(is("val1"))); + assertThat("Inbound baggage bag1", span.baggage().get("bag2"), OptionalMatcher.optionalValue(is("val2"))); } @Test @@ -161,7 +161,7 @@ void testBaggageAddedAfterActivation() { } private void checkBaggage(Tracer tracer, Span span, Supplier spanContextSupplier) { - String value = span.baggage(BAGGAGE_KEY).orElseThrow(); + String value = span.baggage().get(BAGGAGE_KEY).orElseThrow(); assertThat("baggage value right after set", value, Matchers.is(Matchers.equalTo(BAGGAGE_VALUE))); // Inject the span (context) into the consumer diff --git a/tracing/providers/opentracing/src/main/java/io/helidon/tracing/providers/opentracing/OpenTracingSpan.java b/tracing/providers/opentracing/src/main/java/io/helidon/tracing/providers/opentracing/OpenTracingSpan.java index 841ecc406f6..3bef0f1df54 100644 --- a/tracing/providers/opentracing/src/main/java/io/helidon/tracing/providers/opentracing/OpenTracingSpan.java +++ b/tracing/providers/opentracing/src/main/java/io/helidon/tracing/providers/opentracing/OpenTracingSpan.java @@ -209,7 +209,7 @@ public Span baggage(String key, String value) { @Override public Optional baggage(String key) { - return delegate.baggage(key); + return delegate.baggage().get(key); } @Override diff --git a/tracing/providers/opentracing/src/test/java/io/helidon/tracing/providers/opentracing/TestBaggageApi.java b/tracing/providers/opentracing/src/test/java/io/helidon/tracing/providers/opentracing/TestBaggageApi.java index ed5e6f224c3..cbb1bd76629 100644 --- a/tracing/providers/opentracing/src/test/java/io/helidon/tracing/providers/opentracing/TestBaggageApi.java +++ b/tracing/providers/opentracing/src/test/java/io/helidon/tracing/providers/opentracing/TestBaggageApi.java @@ -48,7 +48,7 @@ void testWritableBaggageFromSpan() { baggage.set("keyB", "valB"); assertThat("Assigned baggage via baggage API value from span", - span.baggage("keyB"), + span.baggage().get("keyB"), OptionalMatcher.optionalValue(is(equalTo("valB")))); assertThat("Assigned via baggage API value is present", baggage.containsKey("keyB"), is(true)); assertThat("Assigned via baggage API value from baggage API", From 26e3548b19863f49c26d855164e70476a4efc08e Mon Sep 17 00:00:00 2001 From: Andrei Arlou Date: Tue, 30 Jul 2024 15:08:53 +0300 Subject: [PATCH 03/37] 4.x: Clarify javadoc for HealthCheckResponse.Builder.status(boolean) (#9043) --- .../src/main/java/io/helidon/health/HealthCheckResponse.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/health/health/src/main/java/io/helidon/health/HealthCheckResponse.java b/health/health/src/main/java/io/helidon/health/HealthCheckResponse.java index 1389855d3a1..d92d0ad57ac 100644 --- a/health/health/src/main/java/io/helidon/health/HealthCheckResponse.java +++ b/health/health/src/main/java/io/helidon/health/HealthCheckResponse.java @@ -60,7 +60,7 @@ enum Status { */ DOWN, /** - * This health check failed with an exception that was not excpected. + * This health check failed with an exception that was not expected. */ ERROR } @@ -94,7 +94,7 @@ public Builder status(Status status) { /** * Status of health check, defaults to {@link HealthCheckResponse.Status#UP}. * - * @param status status as a boolean ({@code true} for {@link HealthCheckResponse.Status#UP}) + * @param status status as a boolean ({@code true} for {@link HealthCheckResponse.Status#UP}), ({@code false} for {@link HealthCheckResponse.Status#DOWN}) * @return updated builder */ public Builder status(boolean status) { From 35eb5acf4d2fc666aaa50e06c4457ba3bfe30f9a Mon Sep 17 00:00:00 2001 From: Thibault Vallin Date: Tue, 30 Jul 2024 20:28:33 +0200 Subject: [PATCH 04/37] 4.x: Document supported GraalVM version for native-image (#8938) * Add GraalVM specific version --- docs/src/main/asciidoc/includes/prerequisites.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/main/asciidoc/includes/prerequisites.adoc b/docs/src/main/asciidoc/includes/prerequisites.adoc index b85ce9e10be..58a960ba847 100644 --- a/docs/src/main/asciidoc/includes/prerequisites.adoc +++ b/docs/src/main/asciidoc/includes/prerequisites.adoc @@ -1,6 +1,6 @@ /////////////////////////////////////////////////////////////////////////////// - Copyright (c) 2022, 2023 Oracle and/or its affiliates. + Copyright (c) 2022, 2024 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. @@ -144,7 +144,7 @@ export JAVA_HOME=/usr/lib/jvm/jdk-21 [role="flex, sm7"] |======= include::prerequisites.adoc[tag=prerequisites-table-contents] -| https://www.graalvm.org/release-notes/JDK_21/[GraalVM for JDK 21]| +| https://www.graalvm.org/release-notes/JDK_21/[GraalVM for JDK 21]| `native-image` support requires GraalVM for JDK 21. When running in the Graal JVM (not native-image) Helidon supports GraalVM for JDK 21 or newer. |======= From 0659ec7e4cd05680db0f95a160fd0b0ca4870028 Mon Sep 17 00:00:00 2001 From: Tomas Langer Date: Tue, 30 Jul 2024 21:34:07 +0200 Subject: [PATCH 05/37] Use Helidon metadata format (HSON) for service registry generated file. (#9061) Add format description. Add module that can be used both from code generator and from runtime to read the service registry metadata. --- all/pom.xml | 4 + bom/pom.xml | 5 + .../java/io/helidon/codegen/apt/AptFiler.java | 16 ++ .../codegen/apt/FilerResourceImpl.java | 89 +++++++++++ .../java/io/helidon/codegen/CodegenFiler.java | 12 ++ .../io/helidon/codegen/FilerResource.java | 42 ++++++ .../extension/HelidonReflectionFeature.java | 4 +- service/README.md | 35 ++++- service/codegen/pom.xml | 8 + .../codegen/HelidonMetaInfServices.java | 142 ++++++------------ .../ServiceRegistryCodegenExtension.java | 34 ++--- .../codegen/src/main/java/module-info.java | 3 + service/metadata/pom.xml | 51 +++++++ .../service/metadata}/DescriptorMetadata.java | 26 +++- .../metadata/DescriptorMetadataImpl.java | 81 ++++++++++ .../helidon/service/metadata/Descriptors.java | 67 +++++++++ .../service/metadata/package-info.java | 25 +++ .../metadata/src/main/java/module-info.java | 27 ++++ service/pom.xml | 1 + service/registry/pom.xml | 8 + .../registry/CoreServiceDiscovery.java | 137 +++++++++-------- .../service/registry/CoreServiceRegistry.java | 10 +- .../service/registry/DescriptorHandler.java | 30 ++++ .../io/helidon/service/registry/Service.java | 4 +- .../service/registry/ServiceDiscovery.java | 13 +- .../registry/src/main/java/module-info.java | 9 +- .../resource-config.json | 2 +- 27 files changed, 668 insertions(+), 217 deletions(-) create mode 100644 codegen/apt/src/main/java/io/helidon/codegen/apt/FilerResourceImpl.java create mode 100644 codegen/codegen/src/main/java/io/helidon/codegen/FilerResource.java create mode 100644 service/metadata/pom.xml rename service/{registry/src/main/java/io/helidon/service/registry => metadata/src/main/java/io/helidon/service/metadata}/DescriptorMetadata.java (56%) create mode 100644 service/metadata/src/main/java/io/helidon/service/metadata/DescriptorMetadataImpl.java create mode 100644 service/metadata/src/main/java/io/helidon/service/metadata/Descriptors.java create mode 100644 service/metadata/src/main/java/io/helidon/service/metadata/package-info.java create mode 100644 service/metadata/src/main/java/module-info.java create mode 100644 service/registry/src/main/java/io/helidon/service/registry/DescriptorHandler.java diff --git a/all/pom.xml b/all/pom.xml index 5b94f055c13..0e02a55378b 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -1090,6 +1090,10 @@ io.helidon.inject.configdriven helidon-inject-configdriven-processor + + io.helidon.service + helidon-service-metadata + io.helidon.service helidon-service-registry diff --git a/bom/pom.xml b/bom/pom.xml index 279b34e57e8..92948eff2a0 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -1436,6 +1436,11 @@ + + io.helidon.service + helidon-service-metadata + ${helidon.version} + io.helidon.service helidon-service-registry diff --git a/codegen/apt/src/main/java/io/helidon/codegen/apt/AptFiler.java b/codegen/apt/src/main/java/io/helidon/codegen/apt/AptFiler.java index 84a7bbf2fab..df4cc10db60 100644 --- a/codegen/apt/src/main/java/io/helidon/codegen/apt/AptFiler.java +++ b/codegen/apt/src/main/java/io/helidon/codegen/apt/AptFiler.java @@ -17,6 +17,7 @@ package io.helidon.codegen.apt; import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; @@ -35,6 +36,7 @@ import io.helidon.codegen.CodegenException; import io.helidon.codegen.CodegenFiler; import io.helidon.codegen.CodegenOptions; +import io.helidon.codegen.FilerResource; import io.helidon.codegen.FilerTextResource; import io.helidon.codegen.IndentType; import io.helidon.codegen.classmodel.ClassModel; @@ -107,6 +109,20 @@ public FilerTextResource textResource(String location, Object... originatingElem } } + @Override + public FilerResource resource(String location, Object... originatingElements) { + try { + var resource = filer.getResource(StandardLocation.CLASS_OUTPUT, "", location); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (var is = resource.openInputStream()) { + is.transferTo(baos); + } + return new FilerResourceImpl(filer, location, toElements(originatingElements), resource, baos.toByteArray()); + } catch (IOException e) { + return new FilerResourceImpl(filer, location, toElements(originatingElements)); + } + } + private Object originatingElement(Element[] elements, Object alternative) { if (elements.length == 0) { return alternative; diff --git a/codegen/apt/src/main/java/io/helidon/codegen/apt/FilerResourceImpl.java b/codegen/apt/src/main/java/io/helidon/codegen/apt/FilerResourceImpl.java new file mode 100644 index 00000000000..4f1915bf248 --- /dev/null +++ b/codegen/apt/src/main/java/io/helidon/codegen/apt/FilerResourceImpl.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2024 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.codegen.apt; + +import java.util.Arrays; + +import javax.annotation.processing.Filer; +import javax.lang.model.element.Element; +import javax.tools.FileObject; +import javax.tools.StandardLocation; + +import io.helidon.codegen.CodegenException; +import io.helidon.codegen.FilerResource; + +class FilerResourceImpl implements FilerResource { + private final Filer filer; + private final String location; + private final Element[] originatingElements; + private final FileObject originalResource; // may be null + + private byte[] currentBytes; + + private boolean modified; + + FilerResourceImpl(Filer filer, String location, Element[] originatingElements) { + this.filer = filer; + this.location = location; + this.originatingElements = originatingElements; + this.originalResource = null; + this.currentBytes = new byte[0]; + } + + FilerResourceImpl(Filer filer, + String location, + Element[] originatingElements, + FileObject originalResource, + byte[] existingBytes) { + this.filer = filer; + this.location = location; + this.originatingElements = originatingElements; + this.originalResource = originalResource; + this.currentBytes = existingBytes; + } + + @Override + public byte[] bytes() { + return Arrays.copyOf(currentBytes, currentBytes.length); + } + + @Override + public void bytes(byte[] newBytes) { + currentBytes = Arrays.copyOf(newBytes, newBytes.length); + modified = true; + } + + @Override + public void write() { + if (modified) { + if (originalResource != null) { + originalResource.delete(); + } + try { + FileObject newResource = filer.createResource(StandardLocation.CLASS_OUTPUT, + "", + location, + originatingElements); + try (var os = newResource.openOutputStream()) { + os.write(currentBytes); + } + } catch (Exception e) { + throw new CodegenException("Failed to create resource: " + location, e); + } + } + } +} diff --git a/codegen/codegen/src/main/java/io/helidon/codegen/CodegenFiler.java b/codegen/codegen/src/main/java/io/helidon/codegen/CodegenFiler.java index f4b2ab46ac2..d8381653f8f 100644 --- a/codegen/codegen/src/main/java/io/helidon/codegen/CodegenFiler.java +++ b/codegen/codegen/src/main/java/io/helidon/codegen/CodegenFiler.java @@ -64,6 +64,18 @@ default FilerTextResource textResource(String location, Object... originatingEle throw new UnsupportedOperationException("Method textResource not implemented yet on " + getClass().getName()); } + /** + * A text resource that can be updated in the output. + * Note that the resource can only be written once per processing round. + * + * @param location location to read/write to in the classes output directory + * @param originatingElements elements that caused this file to be generated + * @return the resource that can be used to update the file + */ + default FilerResource resource(String location, Object... originatingElements) { + throw new UnsupportedOperationException("Method resource not implemented yet on " + getClass().getName()); + } + /** * Write a {@code META-INF/services} file for a specific provider interface and implementation(s). * diff --git a/codegen/codegen/src/main/java/io/helidon/codegen/FilerResource.java b/codegen/codegen/src/main/java/io/helidon/codegen/FilerResource.java new file mode 100644 index 00000000000..45d19079bdc --- /dev/null +++ b/codegen/codegen/src/main/java/io/helidon/codegen/FilerResource.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024 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.codegen; + +/** + * A resource from output (such as {@code target/META-INF/helidon}) that can have existing + * values, and may be replaced with a new value. + */ +public interface FilerResource { + /** + * Existing bytes of the resource. Returns empty array, if the resource does not exist or is empty. + * + * @return bytes of the resource + */ + byte[] bytes(); + + /** + * New bytes of the resource. + * + * @param newBytes new bytes to {@link #write()} to the resource file + */ + void bytes(byte[] newBytes); + + /** + * Writes the new bytes to the output. This operation can only be called once per codegen round. + */ + void write(); +} diff --git a/integrations/graal/native-image-extension/src/main/java/io/helidon/integrations/graal/nativeimage/extension/HelidonReflectionFeature.java b/integrations/graal/native-image-extension/src/main/java/io/helidon/integrations/graal/nativeimage/extension/HelidonReflectionFeature.java index eb95dd04bf5..9386dde6199 100644 --- a/integrations/graal/native-image-extension/src/main/java/io/helidon/integrations/graal/nativeimage/extension/HelidonReflectionFeature.java +++ b/integrations/graal/native-image-extension/src/main/java/io/helidon/integrations/graal/nativeimage/extension/HelidonReflectionFeature.java @@ -35,7 +35,7 @@ import io.helidon.common.features.HelidonFeatures; import io.helidon.common.types.TypeName; import io.helidon.logging.common.LogConfig; -import io.helidon.service.registry.DescriptorMetadata; +import io.helidon.service.registry.DescriptorHandler; import io.helidon.service.registry.ServiceDiscovery; import io.helidon.service.registry.ServiceLoader__ServiceDescriptor; import io.helidon.service.registry.ServiceRegistryConfig; @@ -190,7 +190,7 @@ private void processServiceDescriptors(BeforeAnalysisContext context) { sd.allMetadata() .stream() - .map(DescriptorMetadata::descriptor) + .map(DescriptorHandler::descriptor) .filter(it -> it instanceof ServiceLoader__ServiceDescriptor) .map(it -> (ServiceLoader__ServiceDescriptor) it) .map(ServiceLoader__ServiceDescriptor::serviceType) diff --git a/service/README.md b/service/README.md index 87849dd7f26..4925031ea7c 100644 --- a/service/README.md +++ b/service/README.md @@ -98,14 +98,39 @@ reflection (the class, and the field). ### Registry file format -The service registry uses a `service.registry` in `META-INF/helidon` directory to store the main metadata of +The service registry uses a `service-registry.json` file in `META-INF/helidon` directory to store the main metadata of the service. This is to allow proper ordering of services (Service weight is one of the information stored) and lazy loading of services (which is the approach chosen in the core service registry). -The format is as follows: - -``` -registry-type:service-descriptor-type:weight(double):contracts(comma separated) +The format is as follows (using `//` to comment sections, not part of the format): + +```json +// root is an array of modules (we always generate a single module, but this allows a combined array, i.e. when using shading +[ + { + // version of the metadata file, defaults to 1 (and will always default to 1) + "version": 1, + // name of the module + "module": "io.helidon.example", + // all services in this module + "services": [ + { + // version of the service descriptor, defaults to 1 (and will always default to 1) + "version": 1, + // core (Service registry) or inject (Service Injection), defaults to core + "type": "inject", + // weight, defaults to 100 + "weight": 91.4, + // class of the service descriptor - generated type that contains public constant INSTANCE + "descriptor": "io.helidon.example.ServiceImpl__ServiceDescriptor", + // all contracts this service implements + "contracts": [ + "io.helidon.example.ServiceApi" + ] + } + ] + } +] ``` Example: diff --git a/service/codegen/pom.xml b/service/codegen/pom.xml index 48c5305d120..600db06adc7 100644 --- a/service/codegen/pom.xml +++ b/service/codegen/pom.xml @@ -51,5 +51,13 @@ io.helidon.codegen helidon-codegen-class-model + + io.helidon.metadata + helidon-metadata-hson + + + io.helidon.service + helidon-service-metadata + diff --git a/service/codegen/src/main/java/io/helidon/service/codegen/HelidonMetaInfServices.java b/service/codegen/src/main/java/io/helidon/service/codegen/HelidonMetaInfServices.java index 363d41c2aa7..425c0dfad2d 100644 --- a/service/codegen/src/main/java/io/helidon/service/codegen/HelidonMetaInfServices.java +++ b/service/codegen/src/main/java/io/helidon/service/codegen/HelidonMetaInfServices.java @@ -16,23 +16,25 @@ package io.helidon.service.codegen; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.TreeSet; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import io.helidon.codegen.CodegenException; import io.helidon.codegen.CodegenFiler; -import io.helidon.codegen.FilerTextResource; -import io.helidon.common.types.Annotation; -import io.helidon.common.types.TypeName; +import io.helidon.codegen.FilerResource; +import io.helidon.metadata.hson.Hson; +import io.helidon.service.metadata.DescriptorMetadata; +import io.helidon.service.metadata.Descriptors; -import static io.helidon.codegen.CodegenUtil.generatedAnnotation; +import static io.helidon.service.metadata.Descriptors.SERVICE_REGISTRY_LOCATION; /** * Support for reading and writing Helidon services to the resource. @@ -45,18 +47,13 @@ * The service descriptor is then discoverable at runtime through our own resource in {@value #SERVICES_RESOURCE}. */ class HelidonMetaInfServices { - /** - * Location of the Helidon meta services file. - */ - static final String SERVICES_RESOURCE = "META-INF/helidon/service.registry"; + private final FilerResource services; + private final String moduleName; + private final Set descriptors; - private final FilerTextResource services; - private final List comments; - private final Set descriptors; - - private HelidonMetaInfServices(FilerTextResource services, List comments, Set descriptors) { + private HelidonMetaInfServices(FilerResource services, String moduleName, Set descriptors) { this.services = services; - this.comments = comments; + this.moduleName = moduleName; this.descriptors = descriptors; } @@ -64,39 +61,23 @@ private HelidonMetaInfServices(FilerTextResource services, List comments * Create new instance from the current filer. * * @param filer filer to find the file, and to write it - * @param generator generator used in generated comment if we are creating a new file - * @param trigger trigger that caused this file to be created (can be same as generator) * @param moduleName module that is being built * @return a new instance of the service metadata manager */ - static HelidonMetaInfServices create(CodegenFiler filer, TypeName generator, TypeName trigger, String moduleName) { - FilerTextResource services = filer.textResource(SERVICES_RESOURCE); - - List comments = new ArrayList<>(); - Set descriptors = new TreeSet<>(Comparator.comparing(DescriptorMeta::descriptor)); - - for (String line : services.lines()) { - String trimmedLine = line.trim(); - if (trimmedLine.startsWith("#")) { - comments.add(line); - } else if (trimmedLine.isEmpty()) { - // ignore empty lines - continue; - } else { - descriptors.add(DescriptorMeta.parse(trimmedLine)); - } - } + static HelidonMetaInfServices create(CodegenFiler filer, String moduleName) { + FilerResource serviceRegistryMetadata = filer.resource(SERVICE_REGISTRY_LOCATION); + byte[] bytes = serviceRegistryMetadata.bytes(); - if (comments.isEmpty()) { - // @Generated - comments.add("# Generated list of service descriptors in module " + moduleName); - comments.add("# " + toAnnotationText(generatedAnnotation(generator, - trigger, - TypeName.create("io.helidon.services.ServicesMeta"), - "1", - ""))); + Set descriptors = new TreeSet<>(Comparator.comparing(DescriptorMetadata::descriptorType)); + + if (bytes.length != 0) { + Hson.Array moduleRegistry = Hson.parse(new ByteArrayInputStream(bytes)) + .asArray(); + descriptors.addAll(Descriptors.descriptors("helidon-service-codegen for " + moduleName, + moduleRegistry)); } - return new HelidonMetaInfServices(services, comments, descriptors); + + return new HelidonMetaInfServices(serviceRegistryMetadata, moduleName, descriptors); } /** @@ -105,7 +86,7 @@ static HelidonMetaInfServices create(CodegenFiler filer, TypeName generator, Typ * * @param services service descriptor metadata to add */ - void addAll(Collection services) { + void addAll(Collection services) { services.forEach(this::add); } @@ -115,9 +96,9 @@ void addAll(Collection services) { * * @param service service descriptor metadata to add */ - void add(DescriptorMeta service) { + void add(DescriptorMetadata service) { // if it is the same descriptor class, remove it - descriptors.removeIf(it -> it.descriptor().equals(service.descriptor())); + descriptors.removeIf(it -> it.descriptorType().equals(service.descriptorType())); // always add the new descriptor (either it does not exist, or it was deleted) descriptors.add(service); @@ -127,60 +108,23 @@ void add(DescriptorMeta service) { * Write the file to output. */ void write() { - List lines = new ArrayList<>(comments); + var root = Hson.objectBuilder() + .set("module", moduleName); + List servicesHson = new ArrayList<>(); + descriptors.stream() - .map(DescriptorMeta::toLine) - .forEach(lines::add); - services.lines(lines); - services.write(); - } + .map(DescriptorMetadata::toHson) + .forEach(servicesHson::add); - private static String toAnnotationText(Annotation annotation) { - List valuePairs = new ArrayList<>(); - Map annotationValues = annotation.values(); - annotationValues.forEach((key, value) -> valuePairs.add(key + "=\"" + value + "\"")); - return "@" + annotation.typeName().fqName() + "(" + String.join(", ", valuePairs) + ")"; - } + root.setObjects("services", servicesHson); - /** - * Metadata of a single service descriptor. - * This information is stored within the Helidon specific {code META-INF} services file. - * - * @param registryType type of registry, such as {@code core} - * @param descriptor descriptor type - * @param weight weight of the service - * @param contracts contracts the service implements/provides - */ - record DescriptorMeta(String registryType, TypeName descriptor, double weight, Set contracts) { - private static DescriptorMeta parse(String line) { - String[] elements = line.split(":"); - if (elements.length < 4) { - throw new CodegenException("Failed to parse line from existing META-INF/helidon/service.registry: " - + line + ", expecting registry-type:serviceDescriptor:weight:contracts"); - } - Set contracts = Stream.of(elements[3].split(",")) - .map(String::trim) - .map(TypeName::create) - .collect(Collectors.toSet()); - - try { - return new DescriptorMeta(elements[0], - TypeName.create(elements[1]), - Double.parseDouble(elements[2]), - contracts); - } catch (NumberFormatException e) { - throw new CodegenException("Unexpected line structure in service.registry. Third element should be weight " - + "(double). Got: " + line + ", message: " + e.getMessage(), e); - } + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (var pw = new PrintWriter(new OutputStreamWriter(baos, StandardCharsets.UTF_8))) { + Hson.Array.create(List.of(root.build())) + .write(pw); } - private String toLine() { - return registryType + ":" - + descriptor.fqName() + ":" - + weight + ":" - + contracts.stream() - .map(TypeName::fqName) - .collect(Collectors.joining(",")); - } + services.bytes(baos.toByteArray()); + services.write(); } } diff --git a/service/codegen/src/main/java/io/helidon/service/codegen/ServiceRegistryCodegenExtension.java b/service/codegen/src/main/java/io/helidon/service/codegen/ServiceRegistryCodegenExtension.java index 0b60de1a369..be5b29c9d98 100644 --- a/service/codegen/src/main/java/io/helidon/service/codegen/ServiceRegistryCodegenExtension.java +++ b/service/codegen/src/main/java/io/helidon/service/codegen/ServiceRegistryCodegenExtension.java @@ -40,7 +40,7 @@ import io.helidon.common.types.TypeName; import io.helidon.common.types.TypeNames; import io.helidon.common.types.TypedElementInfo; -import io.helidon.service.codegen.HelidonMetaInfServices.DescriptorMeta; +import io.helidon.service.metadata.DescriptorMetadata; import static io.helidon.service.codegen.ServiceCodegenTypes.SERVICE_ANNOTATION_DESCRIPTOR; @@ -48,19 +48,15 @@ * Handles processing of all extensions, creates context and writes types. */ class ServiceRegistryCodegenExtension implements CodegenExtension { - private static final TypeName TYPE = TypeName.create(ServiceRegistryCodegenExtension.class); - private final Map> typeToExtensions = new HashMap<>(); private final Map> extensionPredicates = new IdentityHashMap<>(); - private final Set generatedServiceDescriptors = new HashSet<>(); - private final TypeName generator; + private final Set generatedServiceDescriptors = new HashSet<>(); private final RegistryCodegenContext ctx; private final List extensions; private final String module; private ServiceRegistryCodegenExtension(CodegenContext ctx, TypeName generator) { this.ctx = RegistryCodegenContext.create(ctx); - this.generator = generator; this.module = ctx.moduleName().orElse(null); ServiceExtension serviceExtension = new ServiceExtension(this.ctx); @@ -105,10 +101,10 @@ public void process(io.helidon.codegen.RoundContext roundContext) { String registryType = descriptorAnnot.stringValue("registryType").orElse("core"); // predefined service descriptor - generatedServiceDescriptors.add(new DescriptorMeta(registryType, - typeInfo.typeName(), - weight, - contracts)); + generatedServiceDescriptors.add(DescriptorMetadata.create(registryType, + typeInfo.typeName(), + weight, + contracts)); } if (roundContext.availableAnnotations().size() == 1 && roundContext.availableAnnotations() @@ -152,8 +148,6 @@ private void addDescriptorsToServiceMeta() { moduleName = "unnamed/" + packageName + (ctx.scope().isProduction() ? "" : "/" + ctx.scope().name()); } HelidonMetaInfServices services = HelidonMetaInfServices.create(ctx.filer(), - TYPE, - TYPE, moduleName); services.addAll(generatedServiceDescriptors); @@ -169,10 +163,10 @@ private void writeNewTypes() { for (var descriptor : descriptors) { ClassCode classCode = descriptor.classCode(); ClassModel classModel = classCode.classModel().build(); - generatedServiceDescriptors.add(new DescriptorMeta(descriptor.registryType(), - classCode.newType(), - descriptor.weight(), - descriptor.contracts())); + generatedServiceDescriptors.add(DescriptorMetadata.create(descriptor.registryType(), + classCode.newType(), + descriptor.weight(), + descriptor.contracts())); filer.writeSourceFile(classModel, classCode.originatingElements()); } descriptors.clear(); @@ -263,11 +257,11 @@ private Set annotations(TypeInfo theTypeInfo) { return result; } - private String topLevelPackage(Set typeNames) { - String thePackage = typeNames.iterator().next().descriptor().packageName(); + private String topLevelPackage(Set typeNames) { + String thePackage = typeNames.iterator().next().descriptorType().packageName(); - for (DescriptorMeta typeName : typeNames) { - String nextPackage = typeName.descriptor().packageName(); + for (DescriptorMetadata typeName : typeNames) { + String nextPackage = typeName.descriptorType().packageName(); if (nextPackage.length() < thePackage.length()) { thePackage = nextPackage; } diff --git a/service/codegen/src/main/java/module-info.java b/service/codegen/src/main/java/module-info.java index 58bbe69d2ad..a7ecbf9bd08 100644 --- a/service/codegen/src/main/java/module-info.java +++ b/service/codegen/src/main/java/module-info.java @@ -24,6 +24,9 @@ requires transitive io.helidon.codegen.classmodel; requires transitive io.helidon.codegen; + requires io.helidon.metadata.hson; + requires io.helidon.service.metadata; + exports io.helidon.service.codegen; provides io.helidon.codegen.spi.CodegenExtensionProvider diff --git a/service/metadata/pom.xml b/service/metadata/pom.xml new file mode 100644 index 00000000000..26bf61bddf0 --- /dev/null +++ b/service/metadata/pom.xml @@ -0,0 +1,51 @@ + + + + + + io.helidon.service + helidon-service-project + 4.1.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + helidon-service-metadata + Helidon Service Metadata + + Metadata library to read and write service registry information. + + + + + io.helidon.common + helidon-common + + + io.helidon.common + helidon-common-types + + + io.helidon.metadata + helidon-metadata-hson + + + diff --git a/service/registry/src/main/java/io/helidon/service/registry/DescriptorMetadata.java b/service/metadata/src/main/java/io/helidon/service/metadata/DescriptorMetadata.java similarity index 56% rename from service/registry/src/main/java/io/helidon/service/registry/DescriptorMetadata.java rename to service/metadata/src/main/java/io/helidon/service/metadata/DescriptorMetadata.java index c660dae6bb2..6fbc36af9c0 100644 --- a/service/registry/src/main/java/io/helidon/service/registry/DescriptorMetadata.java +++ b/service/metadata/src/main/java/io/helidon/service/metadata/DescriptorMetadata.java @@ -14,15 +14,15 @@ * limitations under the License. */ -package io.helidon.service.registry; +package io.helidon.service.metadata; import java.util.Set; import io.helidon.common.types.TypeName; +import io.helidon.metadata.hson.Hson; /** - * Metadata of a single service descriptor. - * This information is stored within the Helidon specific {code META-INF} services file. + * Metadata of a service descriptor, as stored in Helidon specific file {@value Descriptors#SERVICE_REGISTRY_LOCATION}. */ public interface DescriptorMetadata { /** @@ -30,6 +30,19 @@ public interface DescriptorMetadata { */ String REGISTRY_TYPE_CORE = "core"; + /** + * Create a new instance from descriptor information, i.e. when code generating the descriptor metadata. + * + * @param registryType type of registry, such as {@link #REGISTRY_TYPE_CORE} + * @param descriptor type of the service descriptor (the generated file from {@code helidon-service-codegen}) + * @param weight weight of the service descriptor + * @param contracts contracts the service implements + * @return a new descriptor metadata instance + */ + static DescriptorMetadata create(String registryType, TypeName descriptor, double weight, Set contracts) { + return new DescriptorMetadataImpl(registryType, weight, descriptor, contracts); + } + /** * Type of registry, such as {@code core}. * @@ -60,9 +73,10 @@ public interface DescriptorMetadata { double weight(); /** - * Descriptor instance. + * Create the metadata in Helidon metadata format. This is used by components that store + * the metadata. * - * @return the descriptor + * @return HSON object (similar to JSON) */ - GeneratedService.Descriptor descriptor(); + Hson.Object toHson(); } diff --git a/service/metadata/src/main/java/io/helidon/service/metadata/DescriptorMetadataImpl.java b/service/metadata/src/main/java/io/helidon/service/metadata/DescriptorMetadataImpl.java new file mode 100644 index 00000000000..397a3e39582 --- /dev/null +++ b/service/metadata/src/main/java/io/helidon/service/metadata/DescriptorMetadataImpl.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2024 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.service.metadata; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import io.helidon.common.Weighted; +import io.helidon.common.types.TypeName; +import io.helidon.metadata.hson.Hson; + +record DescriptorMetadataImpl(String registryType, + double weight, + TypeName descriptorType, + Set contracts) implements DescriptorMetadata { + + private static final int CURRENT_DESCRIPTOR_VERSION = 1; + private static final int DEFAULT_DESCRIPTOR_VERSION = 1; + + static DescriptorMetadata create(String moduleName, String location, Hson.Object service) { + int version = service.intValue("version", DEFAULT_DESCRIPTOR_VERSION); + if (version != CURRENT_DESCRIPTOR_VERSION) { + throw new IllegalStateException("Invalid descriptor version: " + version + + " for module \"" + moduleName + "\"" + + " loaded from \"" + location + "\", " + + "expected version: \"" + CURRENT_DESCRIPTOR_VERSION + "\"," + + " descriptor (if available): " + + service.stringValue("descriptor", "N/A")); + } + + String type = service.stringValue("type", REGISTRY_TYPE_CORE); + TypeName descriptor = service.stringValue("descriptor") + .map(TypeName::create) + .orElseThrow(() -> new IllegalStateException("Could not parse service metadata " + + " for module \"" + moduleName + "\"" + + " loaded from \"" + location + "\", " + + "missing \"descriptor\" value")); + double weight = service.doubleValue("weight", Weighted.DEFAULT_WEIGHT); + Set contracts = service.stringArray("contracts") + .orElseGet(List::of) + .stream() + .map(TypeName::create) + .collect(Collectors.toSet()); + + return new DescriptorMetadataImpl(type, weight, descriptor, contracts); + } + + @Override + public Hson.Object toHson() { + var builder = Hson.objectBuilder(); + + if (!registryType.equals(REGISTRY_TYPE_CORE)) { + builder.set("type", registryType); + } + if (weight != Weighted.DEFAULT_WEIGHT) { + builder.set("weight", weight); + } + builder.set("descriptor", descriptorType.fqName()); + builder.setStrings("contracts", contracts.stream() + .map(TypeName::fqName) + .sorted(String.CASE_INSENSITIVE_ORDER) + .collect(Collectors.toUnmodifiableList())); + + return builder.build(); + } +} diff --git a/service/metadata/src/main/java/io/helidon/service/metadata/Descriptors.java b/service/metadata/src/main/java/io/helidon/service/metadata/Descriptors.java new file mode 100644 index 00000000000..c49f1160fd3 --- /dev/null +++ b/service/metadata/src/main/java/io/helidon/service/metadata/Descriptors.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2024 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.service.metadata; + +import java.util.ArrayList; +import java.util.List; + +import io.helidon.metadata.hson.Hson; + +/** + * Service descriptor utilities. + */ +public class Descriptors { + /** + * Location of the Helidon service registry metadata file. + */ + public static final String SERVICE_REGISTRY_LOCATION = "META-INF/helidon/service-registry.json"; + private static final int CURRENT_REGISTRY_VERSION = 1; + private static final int DEFAULT_REGISTRY_VERSION = 1; + + private Descriptors() { + } + + /** + * Get all service descriptors from the array of descriptors discovered from classpath (or other source). + * + * @param location where was thi array obtained (such as "Classpath URL: ...") + * @param moduleRegistries array of modules + * @return a list of descriptor metadata + * @throws java.lang.IllegalStateException in case the format is not as expected + */ + public static List descriptors(String location, Hson.Array moduleRegistries) { + List descriptors = new ArrayList<>(); + + for (Hson.Object moduleRegistry : moduleRegistries.getObjects()) { + String moduleName = moduleRegistry.stringValue("module", "unknown"); + int version = moduleRegistry.intValue("version", DEFAULT_REGISTRY_VERSION); + if (version != CURRENT_REGISTRY_VERSION) { + throw new IllegalStateException("Invalid registry version: " + version + + " for module \"" + moduleName + "\"" + + " loaded from \"" + location + "\", " + + "expected version: \"" + CURRENT_REGISTRY_VERSION + "\""); + } + + moduleRegistry.objectArray("services") + .orElseGet(List::of) + .stream() + .map(it -> DescriptorMetadataImpl.create(moduleName, location, it)) + .forEach(descriptors::add); + } + return descriptors; + } +} diff --git a/service/metadata/src/main/java/io/helidon/service/metadata/package-info.java b/service/metadata/src/main/java/io/helidon/service/metadata/package-info.java new file mode 100644 index 00000000000..19ecfb1619a --- /dev/null +++ b/service/metadata/src/main/java/io/helidon/service/metadata/package-info.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024 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. + */ + +/** + * Metadata for service registry. + *

+ * This module is used both from codegen and from runtime to parser service registry metadata into + * Java objects. + * + * @see io.helidon.service.metadata.Descriptors + */ +package io.helidon.service.metadata; diff --git a/service/metadata/src/main/java/module-info.java b/service/metadata/src/main/java/module-info.java new file mode 100644 index 00000000000..424b07feb01 --- /dev/null +++ b/service/metadata/src/main/java/module-info.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 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. + */ + +/** + * Metadata for service registry. + * + * @see io.helidon.service.metadata + */ +module io.helidon.service.metadata { + requires io.helidon.metadata.hson; + requires io.helidon.common.types; + + exports io.helidon.service.metadata; +} \ No newline at end of file diff --git a/service/pom.xml b/service/pom.xml index 9efc2d258e3..4fdb7bf3b0e 100644 --- a/service/pom.xml +++ b/service/pom.xml @@ -41,6 +41,7 @@ + metadata codegen registry tests diff --git a/service/registry/pom.xml b/service/registry/pom.xml index 6a7355670ad..73eb7b05ce2 100644 --- a/service/registry/pom.xml +++ b/service/registry/pom.xml @@ -56,6 +56,14 @@ io.helidon.common helidon-common-config + + io.helidon.metadata + helidon-metadata-hson + + + io.helidon.service + helidon-service-metadata + io.helidon.common.features helidon-common-features-api diff --git a/service/registry/src/main/java/io/helidon/service/registry/CoreServiceDiscovery.java b/service/registry/src/main/java/io/helidon/service/registry/CoreServiceDiscovery.java index 3219668d9d3..0eea43248a9 100644 --- a/service/registry/src/main/java/io/helidon/service/registry/CoreServiceDiscovery.java +++ b/service/registry/src/main/java/io/helidon/service/registry/CoreServiceDiscovery.java @@ -28,39 +28,43 @@ import java.util.Map; import java.util.ServiceLoader; import java.util.Set; -import java.util.stream.Collectors; import java.util.stream.Stream; import io.helidon.common.LazyValue; import io.helidon.common.Weighted; import io.helidon.common.Weights; import io.helidon.common.types.TypeName; +import io.helidon.metadata.hson.Hson; +import io.helidon.service.metadata.DescriptorMetadata; +import io.helidon.service.metadata.Descriptors; import io.helidon.service.registry.GeneratedService.Descriptor; +import static io.helidon.service.metadata.Descriptors.SERVICE_REGISTRY_LOCATION; import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.function.Predicate.not; class CoreServiceDiscovery implements ServiceDiscovery { private static final System.Logger LOGGER = System.getLogger(CoreServiceDiscovery.class.getName()); - private final List allDescriptors; + private final List allDescriptors; private CoreServiceDiscovery(ServiceRegistryConfig config) { - Map allDescriptors = new LinkedHashMap<>(); + Map allDescriptors = new LinkedHashMap<>(); ClassLoader classLoader = classLoader(); // each line is a type:service-descriptor:weight:contract,contract if (config.discoverServices()) { - classLoader.resources(SERVICES_RESOURCE) - .flatMap(CoreServiceDiscovery::loadLines) - .filter(not(Line::isEmpty)) - .filter(not(Line::isComment)) - .flatMap(DescriptorMeta::parse) - .forEach(it -> allDescriptors.putIfAbsent(it.descriptorType(), it)); + classLoader.resources(SERVICE_REGISTRY_LOCATION) + .forEach(url -> { + loadServices(url) + .map(DescriptorHandlerImpl::new) + .forEach(it -> allDescriptors.putIfAbsent(it.descriptorType(), + it)); + }); } - List result = new ArrayList<>(allDescriptors.values()); + List result = new ArrayList<>(allDescriptors.values()); if (config.discoverServicesFromServiceLoader()) { // each line is a provider type name (and may have zero or more implementations) @@ -68,7 +72,7 @@ private CoreServiceDiscovery(ServiceRegistryConfig config) { .flatMap(CoreServiceDiscovery::loadLines) .filter(not(Line::isEmpty)) .filter(not(Line::isComment)) - .flatMap(DescriptorMeta::parseServiceProvider) + .flatMap(DescriptorHandlerImpl::parseServiceProvider) .forEach(result::add); } @@ -84,7 +88,7 @@ static ServiceDiscovery noop() { } @Override - public List allMetadata() { + public List allMetadata() { return allDescriptors; } @@ -143,8 +147,8 @@ private static Stream loadLines(URL url) { } } - private static DescriptorMeta createServiceProviderDescriptor(TypeName providerType, - ServiceLoader.Provider provider) { + private static DescriptorHandlerImpl createServiceProviderDescriptor(TypeName providerType, + ServiceLoader.Provider provider) { Class serviceClass = provider.type(); double weight = Weights.find(serviceClass, Weighted.DEFAULT_WEIGHT); @@ -156,11 +160,29 @@ private static DescriptorMeta createServiceProviderDescriptor(TypeName providerT } Descriptor descriptor = ServiceLoader__ServiceDescriptor.create(providerType, provider, weight); - return new DescriptorMeta("core", - descriptor.descriptorType(), - weight, - descriptor.contracts(), - LazyValue.create(descriptor)); + return new DescriptorHandlerImpl(DescriptorMetadata.create("core", + descriptor.descriptorType(), + weight, + descriptor.contracts()), + LazyValue.create(descriptor)); + } + + private Stream loadServices(URL url) { + + Hson.Array array; + + try (var stream = url.openStream()) { + array = Hson.parse(stream) + .asArray(); + } catch (IOException e) { + LOGGER.log(Level.WARNING, "Failed to read services from " + url, e); + return Stream.of(); + } + + return Descriptors.descriptors("classpath descriptor " + url, + array) + .stream(); + } private record Line(String source, String line, int lineNumber) { @@ -173,13 +195,11 @@ boolean isComment() { } } - private record DescriptorMeta(String registryType, - TypeName descriptorType, - double weight, - Set contracts, - LazyValue> descriptorSupplier) implements DescriptorMetadata { - DescriptorMeta(String registryType, TypeName descriptorType, double weight, Set contract) { - this(registryType, descriptorType, weight, contract, LazyValue.create(() -> getDescriptorInstance(descriptorType))); + private record DescriptorHandlerImpl(DescriptorMetadata metadata, + LazyValue> descriptorSupplier) implements DescriptorHandler { + + DescriptorHandlerImpl(DescriptorMetadata metadata) { + this(metadata, LazyValue.create(() -> getDescriptorInstance(metadata.descriptorType()))); } @Override @@ -187,7 +207,32 @@ public Descriptor descriptor() { return descriptorSupplier.get(); } - private static Stream parseServiceProvider(Line line) { + @Override + public String registryType() { + return metadata.registryType(); + } + + @Override + public TypeName descriptorType() { + return metadata.descriptorType(); + } + + @Override + public Set contracts() { + return metadata.contracts(); + } + + @Override + public double weight() { + return metadata.weight(); + } + + @Override + public Hson.Object toHson() { + return metadata.toHson(); + } + + private static Stream parseServiceProvider(Line line) { // io.helidon.config.ConfigSource TypeName providerType = TypeName.create(line.line.trim()); @@ -200,49 +245,13 @@ private static Stream parseServiceProvider(Line line) { return serviceLoader.stream() .map(it -> CoreServiceDiscovery.createServiceProviderDescriptor(providerType, it)); } - - private static Stream parse(Line line) { - // core:io.helidon.ContractImpl__ServiceDescriptor:101.3:io.helidon.Contract,io.helidon.Contract2 - // inject:io.helidon.ContractImpl__ServiceDescriptor:101.3:io.helidon.Contract,io.helidon.Contract2 - String[] components = line.line().split(":"); - if (components.length < 4) { - // allow more, if we need more info in the future, to be backward compatible for libraries - LOGGER.log(Level.WARNING, - "Line " + line.lineNumber() + " of " + line.source() - + " is invalid, should be registry-type:service-descriptor:weight:contracts"); - } - try { - String registryType = components[0]; - TypeName descriptor = TypeName.create(components[1]); - double weight = Double.parseDouble(components[2]); - - if (LOGGER.isLoggable(Level.TRACE)) { - LOGGER.log(Level.TRACE, - "Discovered service descriptor %s, weight: %s".formatted(descriptor.fqName(), - weight)); - } - - Set contracts = Stream.of(components[3].split(",")) - .map(String::trim) - .map(TypeName::create) - .collect(Collectors.toSet()); - - return Stream.of(new DescriptorMeta(registryType, descriptor, weight, contracts)); - } catch (RuntimeException e) { - LOGGER.log(Level.WARNING, - "Line " + line.lineNumber() + " of " + line.source() - + " is invalid, should be service-descriptor:weight:contracts", - e); - return Stream.empty(); - } - } } static class NoopServiceDiscovery implements ServiceDiscovery { private static final ServiceDiscovery INSTANCE = new NoopServiceDiscovery(); @Override - public List allMetadata() { + public List allMetadata() { return List.of(); } } diff --git a/service/registry/src/main/java/io/helidon/service/registry/CoreServiceRegistry.java b/service/registry/src/main/java/io/helidon/service/registry/CoreServiceRegistry.java index fd364adba56..39ef78db293 100644 --- a/service/registry/src/main/java/io/helidon/service/registry/CoreServiceRegistry.java +++ b/service/registry/src/main/java/io/helidon/service/registry/CoreServiceRegistry.java @@ -82,8 +82,8 @@ class CoreServiceRegistry implements ServiceRegistry { boolean logUnsupported = LOGGER.isLoggable(Level.TRACE); // and finally add discovered instances - for (DescriptorMetadata descriptorMeta : serviceDiscovery.allMetadata()) { - if (!descriptorMeta.registryType().equals(DescriptorMetadata.REGISTRY_TYPE_CORE)) { + for (DescriptorHandler descriptorMeta : serviceDiscovery.allMetadata()) { + if (!descriptorMeta.registryType().equals(DescriptorHandler.REGISTRY_TYPE_CORE)) { // we can only support core services, others should be handled by other registry implementations if (logUnsupported) { LOGGER.log(Level.TRACE, @@ -173,7 +173,7 @@ private static void addContracts(Map> providers, } } - private Supplier> instanceSupplier(DescriptorMetadata descriptorMeta) { + private Supplier> instanceSupplier(DescriptorHandler descriptorMeta) { LazyValue> serviceInstance = LazyValue.create(() -> instance(descriptorMeta.descriptor())); if (descriptorMeta.contracts().contains(TypeNames.SUPPLIER)) { @@ -319,12 +319,12 @@ public TypeName descriptorType() { } private record DiscoveredDescriptor(CoreServiceRegistry registry, - DescriptorMetadata metadata, + DescriptorHandler metadata, Supplier> instanceSupplier, ReentrantLock lock) implements ServiceProvider { private DiscoveredDescriptor(CoreServiceRegistry registry, - DescriptorMetadata metadata, + DescriptorHandler metadata, Supplier> instanceSupplier) { this(registry, metadata, instanceSupplier, new ReentrantLock()); } diff --git a/service/registry/src/main/java/io/helidon/service/registry/DescriptorHandler.java b/service/registry/src/main/java/io/helidon/service/registry/DescriptorHandler.java new file mode 100644 index 00000000000..d861de61666 --- /dev/null +++ b/service/registry/src/main/java/io/helidon/service/registry/DescriptorHandler.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024 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.service.registry; + +/** + * Metadata of a single service descriptor. + * This information is stored within the Helidon specific {code META-INF} services file. + */ +public interface DescriptorHandler extends io.helidon.service.metadata.DescriptorMetadata { + /** + * Descriptor instance. + * + * @return the descriptor + */ + GeneratedService.Descriptor descriptor(); +} diff --git a/service/registry/src/main/java/io/helidon/service/registry/Service.java b/service/registry/src/main/java/io/helidon/service/registry/Service.java index a8a4889d500..572ef7f9bcf 100644 --- a/service/registry/src/main/java/io/helidon/service/registry/Service.java +++ b/service/registry/src/main/java/io/helidon/service/registry/Service.java @@ -131,12 +131,12 @@ private Service() { /** * Type of service registry that should read this descriptor. Defaults to - * {@value DescriptorMetadata#REGISTRY_TYPE_CORE}, so the descriptor must only implement + * {@value DescriptorHandler#REGISTRY_TYPE_CORE}, so the descriptor must only implement * {@link io.helidon.service.registry.GeneratedService.Descriptor}. * * @return type of registry this descriptor supports */ - String registryType() default DescriptorMetadata.REGISTRY_TYPE_CORE; + String registryType() default DescriptorHandler.REGISTRY_TYPE_CORE; /** * The weight of the service. This is required for predefined descriptors, as we do not want diff --git a/service/registry/src/main/java/io/helidon/service/registry/ServiceDiscovery.java b/service/registry/src/main/java/io/helidon/service/registry/ServiceDiscovery.java index 57cacc8337b..d9074bb2734 100644 --- a/service/registry/src/main/java/io/helidon/service/registry/ServiceDiscovery.java +++ b/service/registry/src/main/java/io/helidon/service/registry/ServiceDiscovery.java @@ -22,18 +22,11 @@ * Access to discovered service metadata. */ public interface ServiceDiscovery { - /** - * A file that contains all services within a module. Each service has an identifier of the registry that - * created it (such as {@code core}), the class of the service descriptor, - * weight of the service, and a list of contracts it implements. - *

- * This file is used by {@link io.helidon.service.registry.ServiceDiscovery} to find services. - */ - String SERVICES_RESOURCE = "META-INF/helidon/service.registry"; /** * A file that contains all service provider interfaces that expose a service for * Java {@link java.util.ServiceLoader} that is used to tell Helidon Service Registry to add implementations to - * the registry to be discoverable in addition to services defined in {@link #SERVICES_RESOURCE}. + * the registry to be discoverable in addition to services defined in + * {@link io.helidon.service.metadata.Descriptors#SERVICE_REGISTRY_LOCATION}. */ String SERVICES_LOADER_RESOURCE = "META-INF/helidon/service.loader"; @@ -70,5 +63,5 @@ static ServiceDiscovery noop() { * * @return all discovered metadata */ - List allMetadata(); + List allMetadata(); } diff --git a/service/registry/src/main/java/module-info.java b/service/registry/src/main/java/module-info.java index 51d7670dd85..c387787882f 100644 --- a/service/registry/src/main/java/module-info.java +++ b/service/registry/src/main/java/module-info.java @@ -22,14 +22,17 @@ * Core service registry, supporting {@link io.helidon.service.registry.Service.Provider}. */ @Feature(value = "registry", - description = "Service Registry", - in = HelidonFlavor.SE, - path = "Registry" + description = "Service Registry", + in = HelidonFlavor.SE, + path = "Registry" ) @Preview module io.helidon.service.registry { requires static io.helidon.common.features.api; + requires io.helidon.service.metadata; + requires io.helidon.metadata.hson; + requires transitive io.helidon.common.config; requires transitive io.helidon.builder.api; requires transitive io.helidon.common.types; diff --git a/service/registry/src/main/resources/META-INF/native-image/io.helidon.service/helidon-service-registry/resource-config.json b/service/registry/src/main/resources/META-INF/native-image/io.helidon.service/helidon-service-registry/resource-config.json index aa0540496bb..1921697dfdb 100644 --- a/service/registry/src/main/resources/META-INF/native-image/io.helidon.service/helidon-service-registry/resource-config.json +++ b/service/registry/src/main/resources/META-INF/native-image/io.helidon.service/helidon-service-registry/resource-config.json @@ -1,7 +1,7 @@ { "resources": [ { - "pattern": "META-INF/helidon/service.registry" + "pattern": "META-INF/helidon/service-registry.json" }, { "pattern": "META-INF/helidon/service.loader" From 2b536d5de1ebb7d83826a0410505a8cade84640e Mon Sep 17 00:00:00 2001 From: Thibault Vallin Date: Wed, 31 Jul 2024 09:38:41 +0200 Subject: [PATCH 06/37] 4.x: Add classesDirectory to failsafe plugin configuration (#9059) --- applications/parent/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/applications/parent/pom.xml b/applications/parent/pom.xml index 9dc148d6fee..e4fec74bd9a 100644 --- a/applications/parent/pom.xml +++ b/applications/parent/pom.xml @@ -89,6 +89,7 @@ false true + ${project.build.outputDirectory} From a3de97988b9e88019553507a4729e862c650e4fc Mon Sep 17 00:00:00 2001 From: Thibault Vallin Date: Wed, 31 Jul 2024 10:27:23 +0200 Subject: [PATCH 07/37] 4.x: Update Keycloak version to 24 in OIDC guide (#8868) Signed-off-by: tvallin --- .../asciidoc/mp/guides/security-oidc.adoc | 137 ++++++++---------- .../asciidoc/se/guides/security-oidc.adoc | 106 +++++++------- .../docs/mp/guides/SecurityOidcSnippets.java | 18 +-- .../docs/se/guides/SecurityOidcSnippets.java | 16 +- 4 files changed, 125 insertions(+), 152 deletions(-) diff --git a/docs/src/main/asciidoc/mp/guides/security-oidc.adoc b/docs/src/main/asciidoc/mp/guides/security-oidc.adoc index 8fc28ce7c83..94080f6cd90 100644 --- a/docs/src/main/asciidoc/mp/guides/security-oidc.adoc +++ b/docs/src/main/asciidoc/mp/guides/security-oidc.adoc @@ -41,7 +41,7 @@ This guide describes the steps required to protect your whole application or a s OIDC is a secure mechanism for an application to contact an identity service. It's built on top of OAuth 2.0 and provides full-fledged authentication and authorization protocols. -== Install Keycloak +== Keycloak Installation === On Docker @@ -50,15 +50,15 @@ To install Keycloak with Docker, open a terminal and make sure the port 8080 is [source,bash] .Enter the following command ---- -docker run -p 8080:8080 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin quay.io/keycloak/keycloak:11.0.2 +docker run -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:24.0.5 start-dev ---- This will start Keycloak on local port 8080. It will create the admin user with username `admin` and password `admin` -Feel free to modify 11.0.2 by any keycloak version of your wish. +Feel free to modify 24.0.5 by another keycloak version. If you are running docker behind a proxy server, make sure it is either configured into docker or disabled. Otherwise, you might face a connection timeout because docker cannot download the required data. -To verify that Keycloak is running correctly, go to the admin console : http://localhost:8080/auth/admin +To verify that Keycloak is running correctly, go to the admin console : http://localhost:8080/admin Log in using the username and password mentioned above: `admin`. You should be logged in successfully, and it prompts the admin console. @@ -70,29 +70,29 @@ In the table Server choose Standalone server distribution. ZIP or Tar format are to download Keycloak. After extracting the archive file, you should have a directory named keycloak followed by the version. For example, -if you chose version 11.0.2, the folder must be named keycloak-11.0.2. +if you chose version 24.0.5, the folder must be named keycloak-24.0.5. Open keycloak folder to make it your current directory. [source,bash] .Run this command from command prompt to open the directory: ---- -cd keycloak-11.0.2 +cd keycloak-24.0.5 ---- -== Start Keycloak +==== Start Keycloak To start keycloak and have it ready for further steps, run the following command. [source,bash] .On Linux run: ---- -bin/standalone.sh +bin/kc.sh start-dev ---- [source,bash] .On Windows run: ---- -bin/standalone.bat +bin\kc.bat start-dev ---- Keycloak runs on localhost:8080 by default. @@ -100,22 +100,19 @@ Keycloak runs on localhost:8080 by default. === Create an Admin User You need to create an admin user because it does not come by default when installing Keycloak. -To do this, open http://localhost:8080/auth in your favorite browser. +To do this, open http://localhost:8080 in your favorite browser. -A window `Welcome to Keycloak` should be prompted. If not, check if any error appear in the terminal. +A window `Create an administrative user` should be prompted. If not, check if any error appear in the terminal. -Fill the form by adding Username and Password. Click on `Create` to create the admin user. - -Above Administration Console should be printed "User created" in a green rectangle. - -To check that the admin user was created correctly, click on Administration user which should redirect you -to a Login form. Enter the Username and Password created earlier to log in. +Fill the form by adding Username and Password. Click on `Create user` to create the admin user. A confirmation message +is displayed and an administrative user is created. Press `Open Administration Console` and use the same credentials +to log in. After successfully logged in, the admin console is prompted. -== Set up Keycloak +== Setup Keycloak -To set up Keycloak properly, go to the admin console: http://localhost:8080/auth/admin +To set up Keycloak properly, go to the admin console: http://localhost:8080/admin If you are using Docker, use Username `admin` and password `admin` as it is the default admin user. Otherwise, use the username and password you used to create the admin user. @@ -135,13 +132,13 @@ application with this realm as it could disturb Keycloak functioning. To create a new realm to manage your application: -. Open Keycloak admin console http://localhost:8080/auth/admin. -. Hover the mouse over the dropdown in the top-left corner where it says `Master`, and press `Add realm`. +. Open Keycloak admin console http://localhost:8080/admin. +. Hover the mouse over the dropdown in the top-left corner where it says `Keycloack`, and press `Create realm`. . Fill the form by adding the realm name, `myRealm` for example. . Click on `Create` to create the new realm. -To verify that your realm is created, in the top-left corner where it said `Master` previously -should be now your realm name or `myRealm` is you followed the example. +To verify that your realm is created, you should see your realm name (or `myRealm` if you followed the example) in the top-left +corner where it said `Keycloack` previously. To switch from a realm to another, hover the realm name, and the other realm created appear in the dropdown. Click on any realm name to change the current realm. Make sure all configuration or modification are saved before changing @@ -154,25 +151,28 @@ A realm contains resources such as client which can be accessed by users. To create a new user: -. Open the Keycloak admin console: http://localhost:8080/auth/admin +. Open the Keycloak admin console: http://localhost:8080/admin . Click on `Users` in the left menu -. Press `Add user` +. Press `Create new user` . Fill the form (Username is the only mandatory field) with this value Username: `myUser` -. Click `Save` +. Click `Create` A new user is just created, but it needs a password to be able to log in. To initialize it, do this: -. Click on `Credentials` at the top of the page, under `Myuser`. +. Click on `Credentials` at the top of the page, next to `Details`. +. Press on `Set Password`. . Fill `Password` and `Password confirmation` with the user password of your choice. . If the `Temporary` field is set to `ON`, the user has to update password on next login. Click `ON` to make it `OFF` and prevent it. -. Press `Set Password`. +. Press `Save`. . A pop-up window is popping off. Click on `Set Password` to confirm the new password. To verify that the new user is created correctly: -. Open the Keycloak account console: http://localhost:8080/auth/realms/myRealm/account. +. Open the Keycloak account console: `http://localhost:8080/realms/myRealm/account`. . Login with `myUser` and password chosen earlier. +. Fill the form with required data. +. Save the user details. You should now be logged-in to the account console where users can manage their accounts. @@ -180,29 +180,31 @@ You should now be logged-in to the account console where users can manage their To create your first client: -. Open the Keycloak admin console: http://localhost:8080/auth/admin. +. Open the Keycloak admin console: http://localhost:8080/admin. . Make sure the current realm is `myRealm` and not `Master`. . Navigate to the left menu, into configure section, click on `Clients`. This window displays a table with every client from the realm. -. Click on `Create`. +. Click on `Create client`. . Fill the following: .. `Client ID` : `myClientID` -.. `Client Protocol` : `openid-connect` -. Press `Save` -.. Modify `Access type` : `confidential` +.. `Client Protocol` : `OpenID Connect` +. Press `Next` +. `Capability config` step +.. Enable `Client authentication` +.. Enable `Authorization` +. Press `Next` .. Update `Valid Redirect URIs` : http://localhost:7987/* -.. Click on `+` to add the new URI. . Click on `Save`. A new tab named `Credentials` is created. Click on it to access this new tab. - Select `Client Authenticator` : `Client ID and Secret` -- Click on `generate secret` to generate client secret. +- The client secret is displayed. Keycloak is now configured and ready. Keep keycloak running on your terminal and open a new tab to set up Helidon. -== Set up Helidon +== Setup Helidon Use the Helidon MP Maven archetype to create a simple project. It will be used as an example to show how to set up Helidon. Replace `{helidon-version}` by the latest helidon version. @@ -257,9 +259,10 @@ security: audience: "account" client-id: "myClientID" # <1> header-use: true - client-secret: "Client secret generated into Keycloak client credential" # <2> - identity-uri: "http://localhost:8080/auth/realms/myRealm" # <3> + client-secret: "changeit" # <2> + identity-uri: "http://localhost:8080/realms/myRealm" # <3> frontend-uri: "http://localhost:7987" # <4> + cookie-use: "false" ---- <1> `client-id` must be the same as the one configure in keycloak. <2> The client secret generate by Keycloak during `Create a client` section. @@ -317,7 +320,7 @@ Helidon and Keycloak are now correctly configured and your application is safe. [source,bash] .Build the application, skipping unit tests, then run it: ---- -mvn package -DskipTests=true +mvn package -DskipTests java -jar target/helidon-quickstart-mp.jar ---- @@ -350,7 +353,7 @@ at the end of this guide, the application will be secured by oidc and the tests In the test folder `helidon-quickstart-mp/src/test`: [source,bash] -.Create a new directory and another one inside +.Create a new directory with configuration file ---- mkdir resources cd resources @@ -362,45 +365,24 @@ Open the application.yaml file you just created. [source,yaml] .Copy these properties into the new application.yaml ---- -app: - greeting: "Hello" - -server: - port: 7987 - host: localhost - security: providers: - - abac: + - type: oidc + enabled: false + - oidc: + enabled: false - http-basic-auth: users: - login: "jack" - password: "jackIsGreat" + password: "changeit" ---- -By adding this new application.yaml, it will append the properties to the application.yaml located into `java/resources`. -The oidc properties are not overridden, and the server cannot decide which security provider to choose. - -Excluding oidc dependency during the test leaves only basic authentication security available for the tests. - -[source,xml] -.Add this plugin to the build ----- - - org.apache.maven.plugins - maven-surefire-plugin - - - io.helidon.microprofile:helidon-microprofile-oidc - - - ----- +By adding this new application.yaml, it will append the properties to the application.yaml located into `main/resources`. +The `oidc` provider is now disabled, and the server will pick `http-basic-auth`. In the `MainTest.java` file, tests need to be modified to pass the application security when accessing `/greet` path with a `GET` method. -The server has now one security provider, basic authentication configured. Next step is to create the test to check that the application is correctly protected. Firstly, create new test method `testHelloWorld` @@ -431,7 +413,7 @@ include::{sourcedir}/mp/guides/SecurityOidcSnippets.java[tag=snippet_4, indent=0 ---- The username and password are encoded and placed inside the header in order to authenticate as jack to access the application. -If the authentication is successful, the application send the `Hello World` back as a `JsonObject`. +If the authentication is successful, the application send the `Hello World` back as a `GreetingMessage`. Now, the project can be built without skipping test. @@ -465,15 +447,14 @@ username and password for authentication. 3. The authorization code is used to get access and refresh token from Keycloak token endpoint. For the first step, paste the following URL into your browser: -`http://localhost:8080/auth/realms/myRealm/protocol/openid-connect/auth?client_id=myClientID&response_type=code`. -The first part of the url `http:/../auth` is the Keycloak endpoint to request an authorization code. Two query +`http://localhost:8080/realms/myRealm/protocol/openid-connect/auth?client_id=myClientID&response_type=code`. Two query parameters are provided, the client id and the response type. Press enter and Keycloak responds with different URL containing a query parameter `code`. You successfully received the authorization code. In order to achieve the third step, we can use Postman to exchange the authorization code for tokens. In Postman, select the Http POST method. Keycloak endpoint to get token is the following: -`http://localhost:8080/auth/realms/myRealm/protocol/openid-connect/token`. +`http://localhost:8080/realms/myRealm/protocol/openid-connect/token`. In the body of the request, select `x-www-form-urlencoded` type. Add the following data: [source,json] @@ -495,7 +476,7 @@ a refresh token. The Direct Access Grants flow is used by REST clients that want to request tokens on behalf of a user. To use Postman to make this request on behalf of `myuser`, select the GET method and enter this URL: -`http://localhost:7987/greet/`. Under `Authorization` tab, select authorization type`OAuth 2.0`. Under it, complete the +`http://localhost:7987/greet/`. Under `Authorization` tab, select authorization type `OAuth 2.0`. Under it, complete the sentence `Add authorization data to` with `Request Headers`, and complete the required fields. [source,json] @@ -504,7 +485,7 @@ sentence `Add authorization data to` with `Request Headers`, and complete the r [ {"key":"Header Prefix","value":"bearer"}, {"key":"Grant type","value":"Password Credentials"}, - {"key":"Access Token URL","value":"http://localhost:8080/auth/realms/myRealm/protocol/openid-connect/token"}, + {"key":"Access Token URL","value":"http://localhost:8080/realms/myRealm/protocol/openid-connect/token"}, {"key":"Client ID","value":"myClientID"}, {"key":"Client Secret","value":"client secret"}, {"key":"Username","value":"myuser"}, @@ -527,7 +508,7 @@ only the user with the required role. Navigate to the GreetResource and find the `getDefaultMessage` with @Authenticate annotation. [source,java] -.Add the @RolesAllowed annotation under the @Authenticate annotation: +.Add the @RolesAllowed annotation: ---- include::{sourcedir}/mp/guides/SecurityOidcSnippets.java[tag=snippet_5, indent=0] ---- @@ -543,10 +524,10 @@ Then, add a user and roles to the `helidon-quickstart-mp/src/test/resources/appl - http-basic-auth: users: - login: "jack" - password: "jackIsGreat" + password: "changeit" roles: [ "admin", "user" ] - login: "john" - password: "johnPassword" + password: "changeit" roles: [ "user" ] ---- diff --git a/docs/src/main/asciidoc/se/guides/security-oidc.adoc b/docs/src/main/asciidoc/se/guides/security-oidc.adoc index 62025d0fb3d..b940b811f52 100644 --- a/docs/src/main/asciidoc/se/guides/security-oidc.adoc +++ b/docs/src/main/asciidoc/se/guides/security-oidc.adoc @@ -32,14 +32,6 @@ For this 20 minute tutorial, you will need the following: include::{rootdir}/includes/prerequisites.adoc[tag=prerequisites] -In addition, you will need to install and configure the following: - -* <> -* <> -* <> -* <> -* <> -* <> == Introduction @@ -47,7 +39,7 @@ This guide describes the steps required to protect your whole application or a s (OIDC) security. OIDC is a secure mechanism for an application to contact an identity service. It's built on top of OAuth 2.0 and provides full-fledged authentication and authorization protocols. -== Keycloak Installation [[Keycloak-Installation]] +== Keycloak Installation === On Docker @@ -56,15 +48,15 @@ To install Keycloak with Docker, open a terminal and make sure the port 8080 is [source,bash] .Enter the following command ---- -docker run -p 8080:8080 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin quay.io/keycloak/keycloak:11.0.2 +docker run -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:24.0.5 start-dev ---- This will start Keycloak on local port 8080. It will create the admin user with username `admin` and password `admin` -Feel free to modify 11.0.2 by any keycloak version of your wish. +Feel free to modify 24.0.5 by another keycloak version. If you are running docker behind a proxy server, make sure it is either configured into docker or disabled. Otherwise, you might face a connection timeout because docker cannot download the required data. -To verify that Keycloak is running correctly, go to the admin console : http://localhost:8080/auth/admin +To verify that Keycloak is running correctly, go to the admin console : http://localhost:8080/admin Log in using the username and password mentioned above: `admin`. You should be logged in successfully, and it prompts the admin console. @@ -76,29 +68,29 @@ In the table Server choose Standalone server distribution. ZIP or Tar format are to download Keycloak. After extracting the archive file, you should have a directory named keycloak followed by the version. For example, -if you chose version 11.0.2, the folder must be named keycloak-11.0.2. +if you chose version 24.0.5, the folder must be named keycloak-24.0.5. Open keycloak folder to make it your current directory. [source,bash] .Run this command from command prompt to open the directory: ---- -cd keycloak-11.0.2 +cd keycloak-24.0.5 ---- -== Start Keycloak +==== Start Keycloak To start keycloak and have it ready for further steps, run the following command. [source,bash] .On Linux run: ---- -bin/standalone.sh +bin/kc.sh start-dev ---- [source,bash] .On Windows run: ---- -bin/standalone.bat +bin\kc.bat start-dev ---- Keycloak runs on localhost:8080 by default. @@ -106,22 +98,19 @@ Keycloak runs on localhost:8080 by default. === Create an Admin User You need to create an admin user because it does not come by default when installing Keycloak. -To do this, open http://localhost:8080/auth in your favorite browser. - -A window `Welcome to Keycloak` should be prompted. If not, check if any error appear in the terminal. - -Fill the form by adding Username and Password. Click on `Create` to create the admin user. +To do this, open http://localhost:8080 in your favorite browser. -Above Administration Console should be printed "User created" in a green rectangle. +A window `Create an administrative user` should be prompted. If not, check if any error appear in the terminal. -To check that the admin user was created correctly, click on Administration user which should redirect you -to a Login form. Enter the Username and Password created earlier to log in. +Fill the form by adding Username and Password. Click on `Create user` to create the admin user. A confirmation message +is displayed and an administrative user is created. Press `Open Administration Console` and use the same credentials +to log in. After successfully logged in, the admin console is prompted. -== Setup Keycloak [[Setup-Keycloak]] +== Setup Keycloak -To set up Keycloak properly, go to the admin console: http://localhost:8080/auth/admin +To set up Keycloak properly, go to the admin console: http://localhost:8080/admin If you are using Docker, use Username `admin` and password `admin` as it is the default admin user. Otherwise, use the username and password you used to create the admin user. @@ -141,13 +130,13 @@ application with this realm as it could disturb Keycloak functioning. To create a new realm to manage your application: -. Open Keycloak admin console http://localhost:8080/auth/admin. -. Hover the mouse over the dropdown in the top-left corner where it says `Master`, and press `Add realm`. +. Open Keycloak admin console http://localhost:8080/admin. +. Hover the mouse over the dropdown in the top-left corner where it says `Keycloack`, and press `Create realm`. . Fill the form by adding the realm name, `myRealm` for example. . Click on `Create` to create the new realm. To verify that your realm is created, you should see your realm name (or `myRealm` if you followed the example) in the top-left - corner where it said `Master` previously + corner where it said `Keycloack` previously. To switch from a realm to another, hover the realm name, and the other realm created appear in the dropdown. Click on any realm name to change the current realm. Make sure all configuration or modification are saved before changing @@ -160,25 +149,27 @@ A realm contains resources such as client which can be accessed by users. To create a new user: -. Open the Keycloak admin console: http://localhost:8080/auth/admin +. Open the Keycloak admin console: http://localhost:8080/admin . Click on `Users` in the left menu -. Press `Add user` +. Press `Create new user` . Fill the form (Username is the only mandatory field) with this value Username: `myUser` -. Click `Save` +. Click `Create` A new user is just created, but it needs a password to be able to log in. To initialize it, do this: -. Click on `Credentials` at the top of the page, under `Myuser`. +. Click on `Credentials` at the top of the page, next to `Details`. +. Press on `Set Password`. . Fill `Password` and `Password confirmation` with the user password of your choice. . If the `Temporary` field is set to `ON`, the user has to update password on next login. Click `ON` to make it `OFF` and prevent it. -. Press `Set Password`. +. Press `Save`. . A pop-up window is popping off. Click on `Set Password` to confirm the new password. To verify that the new user is created correctly: -. Open the Keycloak account console: `http://localhost:8080/auth/realms/myRealm/account`. +. Open the Keycloak account console: `http://localhost:8080/realms/myRealm/account`. . Login with `myUser` and password chosen earlier. +. Fill the form with required data. You should now be logged-in to the account console where users can manage their accounts. @@ -186,29 +177,31 @@ You should now be logged-in to the account console where users can manage their To create your first client: -. Open the Keycloak admin console: http://localhost:8080/auth/admin. +. Open the Keycloak admin console: http://localhost:8080/admin. . Make sure the current realm is `myRealm` and not `Master`. . Navigate to the left menu, into configure section, click on `Clients`. This window displays a table with every client from the realm. -. Click on `Create`. +. Click on `Create client`. . Fill the following: .. `Client ID` : `myClientID` -.. `Client Protocol` : `openid-connect` -. Press `Save` -.. Modify `Access type` : `confidential` +.. `Client Protocol` : `OpenID Connect` +. Press `Next` +. `Capability config` step +.. Enable `Client authentication` +.. Enable `Authorization` +. Press `Next` .. Update `Valid Redirect URIs` : http://localhost:7987/* -.. Click on `+` to add the new URI. . Click on `Save`. A new tab named `Credentials` is created. Click on it to access this new tab. - Select `Client Authenticator` : `Client ID and Secret` -- Click on `generate secret` to generate client secret. +- The client secret is displayed. Keycloak is now configured and ready. Keep keycloak running on your terminal and open a new tab to set up Helidon. -== Setup Helidon [[Setup-Helidon]] +== Setup Helidon Use the Helidon SE Maven archetype to create a simple project. It will be used as an example to show how to set up Helidon. Replace `{helidon-version}` by the latest helidon version. @@ -270,8 +263,8 @@ security: # Adds ABAC Provider - it does not require any configuration - oidc: client-id: "myClientID" # <2> - client-secret: "Client secret generated into Keycloak client credential" # <3> - identity-uri: "http://localhost:8080/auth/realms/myRealm" # <4> + client-secret: "changeit" # <3> + identity-uri: "http://localhost:8080/realms/myRealm" # <4> audience: "account" header-use: "true" # proxy-host should be defined if you operate behind a proxy, can be removed otherwise @@ -323,7 +316,7 @@ Helidon sample is now setup and ready. [source,bash] .Build the application, skipping unit tests, then run it: ---- -mvn package -DskipTests=true +mvn package -DskipTests java -jar target/helidon-quickstart-se.jar ---- @@ -342,7 +335,7 @@ now protected, its access is limited, and the tests are not built to take oidc s From the actual settings, the user needs to log in only once, then Keycloak saves all the connection data. -=== Test Keycloak Process with Postman [[Test-Keycloak-process-with-Postman]] +=== Test Keycloak Process with Postman Keycloak supports many authentication and authorization flows, but only two of them will be shown. This section describes another way you can get an access token or refresh a token or identity token. The identity token contains @@ -352,7 +345,7 @@ token. As these tokens contain sensitive information, they are valid for a very last longer in order to let you manipulate them with Postman. To do so: 1. Open the Keycloak Console. -2. Click on the `Realm Setting` in the left menu. +2. Click on the `Realm Settings` in the left menu. 3. Navigate to the `Tokens` tab. You can increase the access token lifespan. @@ -367,15 +360,14 @@ username and password for authentication. 3. The authorization code is used to get access and refresh token from Keycloak token endpoint. For the first step, paste the following URL into your browser: -`http://localhost:8080/auth/realms/myRealm/protocol/openid-connect/auth?client_id=myClientID&response_type=code`. -The first part of the url `http:/../auth` is the Keycloak endpoint to request an authorization code. Two query +`http://localhost:8080/realms/myRealm/protocol/openid-connect/auth?client_id=myClientID&response_type=code`. Two query parameters are provided, the client id and the response type. Press enter and Keycloak responds with different URL containing a query parameter `code`. You successfully received the authorization code. In order to achieve the third step, we can use Postman to exchange the authorization code for tokens. In Postman, select the Http POST method. Keycloak endpoint to get token is the following: -`http://localhost:8080/auth/realms/myRealm/protocol/openid-connect/token`. +`http://localhost:8080/realms/myRealm/protocol/openid-connect/token`. In the body of the request, select `x-www-form-urlencoded` type. Add the following data: [source,json] @@ -409,7 +401,7 @@ Make sure your Helidon application is running. If it is not, please start it. [ {"key":"Header Prefix","value":"bearer"}, {"key":"Grant type","value":"Password Credentials"}, - {"key":"Access Token URL","value":"http://localhost:8080/auth/realms/myRealm/protocol/openid-connect/token"}, + {"key":"Access Token URL","value":"http://localhost:8080/realms/myRealm/protocol/openid-connect/token"}, {"key":"Client ID","value":"myClientID"}, {"key":"Client Secret","value":"client secret"}, {"key":"Username","value":"myuser"}, @@ -468,7 +460,7 @@ security: - oidc: client-id: "myClientID" # <1> client-secret: "Your client secret" # <2> - identity-uri: "http://localhost:8080/auth/realms/myRealm" + identity-uri: "http://localhost:8080/realms/myRealm" audience: "account" frontend-uri: "http://localhost:7987" server-type: "oidc" @@ -516,7 +508,7 @@ Now, the project can be built without skipping test. mvn clean install ---- -==== Restrict Access to a Specific Role [[Restrict-access-to-a-specific-role]] +==== Restrict Access to a Specific Role To give less access to an endpoint, it is possible to configure user role. So the application will only grant access to the user with the required role. @@ -529,10 +521,10 @@ Add a user and roles to the `helidon-quickstart-se/src/test/resources/applicatio - http-basic-auth: users: - login: "jack" - password: "jackIsGreat" + password: "changeit" roles: [ "admin", "user" ] - login: "john" - password: "johnPassword" + password: "changeit" roles: [ "user" ] ---- diff --git a/docs/src/main/java/io/helidon/docs/mp/guides/SecurityOidcSnippets.java b/docs/src/main/java/io/helidon/docs/mp/guides/SecurityOidcSnippets.java index 217329c8a40..b89a416b22d 100644 --- a/docs/src/main/java/io/helidon/docs/mp/guides/SecurityOidcSnippets.java +++ b/docs/src/main/java/io/helidon/docs/mp/guides/SecurityOidcSnippets.java @@ -36,12 +36,12 @@ class SecurityOidcSnippets { // stub - static JsonObject createResponse(String str) { + static GreetingMessage createResponse(String str) { return null; } // stub - record Message() { + record GreetingMessage() { String getMessage() { return ""; } @@ -51,14 +51,14 @@ String getMessage() { @Authenticated @GET @Produces(MediaType.APPLICATION_JSON) - public JsonObject getDefaultMessage() { + public GreetingMessage getDefaultMessage() { return createResponse("World"); } // end::snippet_1[] // tag::snippet_2[] @Test - void testHellowWorld() { + void testHelloWorld() { } // end::snippet_2[] @@ -75,12 +75,12 @@ void snippet_5(WebTarget target) { void snippet_6(WebTarget target) { // tag::snippet_4[] - String encoding = Base64.getEncoder().encodeToString("jack:jackIsGreat".getBytes()); - Message jsonMessage = target + String encoding = Base64.getEncoder().encodeToString("jack:changeit".getBytes()); + GreetingMessage jsonMessage = target .path("greet") .request() .header(HttpHeaders.AUTHORIZATION, "Basic " + encoding) - .get(Message.class); + .get(GreetingMessage.class); assertThat(jsonMessage.getMessage(), is("Hello World!")); // end::snippet_4[] @@ -90,14 +90,14 @@ class Snippet8 { // tag::snippet_5[] @RolesAllowed("admin") - class MyResource { + class GreetResource { } // end::snippet_5[] } void snippet_9(WebTarget target) { // tag::snippet_6[] - String encoding = Base64.getEncoder().encodeToString("john:johnPassword".getBytes()); + String encoding = Base64.getEncoder().encodeToString("john:changeit".getBytes()); try (Response r = target .path("greet") diff --git a/docs/src/main/java/io/helidon/docs/se/guides/SecurityOidcSnippets.java b/docs/src/main/java/io/helidon/docs/se/guides/SecurityOidcSnippets.java index 665690a3a65..1f382ad550c 100644 --- a/docs/src/main/java/io/helidon/docs/se/guides/SecurityOidcSnippets.java +++ b/docs/src/main/java/io/helidon/docs/se/guides/SecurityOidcSnippets.java @@ -40,9 +40,9 @@ void routing(HttpRouting.Builder routing) { // end::snippet_1[] } - void snippet_2(WebClient webClient) { + void snippet_2(WebClient client) { // tag::snippet_2[] - try (HttpClientResponse response = webClient.get() + try (HttpClientResponse response = client.get() .path("/greet") .request()) { assertThat(response.status(), is(Status.UNAUTHORIZED_401)); @@ -50,10 +50,10 @@ void snippet_2(WebClient webClient) { // end::snippet_2[] } - void snippet_3(WebClient webClient) { + void snippet_3(WebClient client) { // tag::snippet_3[] - String auth = "Basic " + Base64.getEncoder().encodeToString("jack:jackIsGreat".getBytes()); - JsonObject jsonObject = webClient.get() + String auth = "Basic " + Base64.getEncoder().encodeToString("jack:changeit".getBytes()); + JsonObject jsonObject = client.get() .path("/greet") .header(HeaderNames.AUTHORIZATION, auth) .requestEntity(JsonObject.class); @@ -62,10 +62,10 @@ void snippet_3(WebClient webClient) { // end::snippet_3[] } - void snippet_4(WebClient webClient) { + void snippet_4(WebClient client) { // tag::snippet_4[] - String auth = "Basic " + Base64.getEncoder().encodeToString("john:johnPassword".getBytes()); - try (HttpClientResponse response = webClient.get() + String auth = "Basic " + Base64.getEncoder().encodeToString("john:changeit".getBytes()); + try (HttpClientResponse response = client.get() .path("/greet") .header(HeaderNames.AUTHORIZATION, auth) .request()) { From b17941dd26868246ed0c5cf81f24a0fb21396775 Mon Sep 17 00:00:00 2001 From: Tim Quinn Date: Wed, 31 Jul 2024 05:40:46 -0500 Subject: [PATCH 08/37] MP Metrics 5.1 support (#9032) * MP Metrics 5.1 support - recommit to 'untouch' a previously changed but now unchanged file * Copyright, checkstyle fixes * Add some Javadoc text to the new enum * Typo * Move GcTimeType enum to its own public file for proper config handling * Hand-edit generated file until separate bug fix * Improved generated MetricsConfig.adoc file * Fix from Tomas for config generation * Review comments - change TODO comments to commented @Deprecated annotation --- .../metadata/processor/TypeHandlerBase.java | 2 +- dependencies/pom.xml | 2 +- .../io_helidon_metrics_api_MetricsConfig.adoc | 8 +- .../includes/metrics/metrics-config.adoc | 20 + .../includes/metrics/metrics-shared.adoc | 15 + .../metrics/api/DistributionSummary.java | 15 + .../io/helidon/metrics/api/GcTimeType.java | 34 ++ .../metrics/api/MetricsConfigBlueprint.java | 13 + .../io/helidon/metrics/api/NoOpMeter.java | 25 ++ .../java/io/helidon/metrics/api/Timer.java | 15 + .../metrics/api/TestGcTimeTypeChoice.java | 63 +++ .../tests/TestDistributionSummary.java | 47 ++- .../MDistributionStatisticsConfig.java | 227 +++++++++-- .../micrometer/MDistributionSummary.java | 43 ++- .../metrics/providers/micrometer/MTimer.java | 14 +- .../micrometer/MicrometerMetricsFactory.java | 2 +- .../MicrometerPrometheusFormatter.java | 4 +- .../systemmeters/SystemMetersProvider.java | 28 +- .../metrics/DistributionCustomizations.java | 359 ++++++++++++++++++ .../metrics/HelidonHistogram.java | 11 +- .../microprofile/metrics/HelidonSnapshot.java | 9 +- .../microprofile/metrics/HelidonTimer.java | 9 +- .../metrics/MetricsCdiExtension.java | 26 +- .../microprofile/metrics/Registry.java | 11 +- .../metrics/RegistryProducer.java | 14 +- .../metrics/HelloWorldAsyncResponseTest.java | 10 +- .../metrics/HelloWorldResource.java | 7 +- ...ldRestEndpointSimpleTimerDisabledTest.java | 7 +- .../metrics/MetricsMpServiceTest.java | 7 +- .../TestDistributionCustomizations.java | 75 ++++ .../metrics/TestGcTimeCounter.java | 55 +++ .../microprofile/metrics/TestGcTimeGauge.java | 54 +++ microprofile/tests/tck/tck-metrics/pom.xml | 4 + 33 files changed, 1122 insertions(+), 113 deletions(-) create mode 100644 metrics/api/src/main/java/io/helidon/metrics/api/GcTimeType.java create mode 100644 metrics/api/src/test/java/io/helidon/metrics/api/TestGcTimeTypeChoice.java create mode 100644 microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/DistributionCustomizations.java create mode 100644 microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestDistributionCustomizations.java create mode 100644 microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestGcTimeCounter.java create mode 100644 microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestGcTimeGauge.java diff --git a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerBase.java b/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerBase.java index c9ba18cd82f..25dfe3bc57d 100644 --- a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerBase.java +++ b/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerBase.java @@ -197,7 +197,7 @@ Optional toEnum(TypeName type) { } List allowedValuesEnum(ConfiguredOptionData data, TypeElement typeElement) { - if (data.allowedValues().isEmpty()) { + if (!data.allowedValues().isEmpty()) { // this was already processed due to an explicit type defined in the annotation // or allowed values explicitly configured in annotation return data.allowedValues(); diff --git a/dependencies/pom.xml b/dependencies/pom.xml index 98f6aac1ac4..2e07bc33492 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -110,7 +110,7 @@ 2.0 4.0.1 2.1 - 5.0.1 + 5.1.1 3.1.1 3.0 3.0 diff --git a/docs/src/main/asciidoc/config/io_helidon_metrics_api_MetricsConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_metrics_api_MetricsConfig.adoc index 81cfc79293f..75ec7695bea 100644 --- a/docs/src/main/asciidoc/config/io_helidon_metrics_api_MetricsConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_metrics_api_MetricsConfig.adoc @@ -53,13 +53,19 @@ This is a standalone configuration type, prefix from configuration root: `metric |`enabled` |boolean |`true` |Whether metrics functionality is enabled. If metrics are configured to be enabled +|[.line-through]#`gc-time-type`# |GcTimeType (GAUGE, COUNTER) |`GcTimeType.COUNTER` |*Deprecated* Whether the `gc.time` meter should be registered as a gauge (vs. a counter). + The `gc.time` meter is inspired by the MicroProfile Metrics spec, in which the meter was originally checked to + be a counter but starting in 5.1 was checked be a gauge. For the duration of Helidon 4.x users can choose which + type of meter Helidon registers for `gc.time`. + The type of meter to use for registering `gc.time` + @deprecated Provided for backward compatibility only; no replacement |`key-performance-indicators` |xref:{rootdir}/config/io_helidon_metrics_api_KeyPerformanceIndicatorMetricsConfig.adoc[KeyPerformanceIndicatorMetricsConfig] |{nbsp} |Key performance indicator metrics settings. Key performance indicator metrics settings |`permit-all` |boolean |`true` |Whether to allow anybody to access the endpoint. Whether to permit access to metrics endpoint to anybody, defaults to `true` - @see #roles() + See roles() |`rest-request-enabled` |boolean |`false` |Whether automatic REST request metrics should be measured. True/false diff --git a/docs/src/main/asciidoc/includes/metrics/metrics-config.adoc b/docs/src/main/asciidoc/includes/metrics/metrics-config.adoc index 7c99c704616..91c76d059e3 100644 --- a/docs/src/main/asciidoc/includes/metrics/metrics-config.adoc +++ b/docs/src/main/asciidoc/includes/metrics/metrics-config.adoc @@ -56,6 +56,26 @@ ifdef::mp-flavor[`application`] |==== -- + +[[controlling-gc-time]] +=== Controlling the {metric_uc} Type for `gc.time` +To date Helidon 4 releases have implemented the system-provided {metric} `gc.time` as a counter. +In fact, a gauge is more suitable for the approximate time the JVM has spent doing garbage +ifdef::se-flavor[collection.] +ifdef::mp-flavor[] +collection, and beginning with MicroProfile Metrics 5.1 the TCK relies on `gc.time` being a gauge. +endif::mp-flavor[] + +Helidon {helidon-version} continues to use a counter by default to preserve backward compatibility, but you can choose to use a gauge by setting the configuration property `metrics.gc-time-type` to `gauge`. +You can also set the config property to `counter` which is the default. + +Why should you care? +In fact, this distinction might not make a difference for many users. +But for others the differences between the programmatic APIs for `Counter` and `Gauge` would affect application code that works directly with the `gc-time` +{metric}. Further, the difference in output--particularly in the OpenMetrics/Prometheus format--might affect their application or downstream monitoring tools. + +The ability to choose the {metric} type for `gc.time` is deprecated and is planned for removal in a future major release of Helidon at which time Helidon will always use a gauge. + // end::config-intro[] // tag::config-examples[] diff --git a/docs/src/main/asciidoc/includes/metrics/metrics-shared.adoc b/docs/src/main/asciidoc/includes/metrics/metrics-shared.adoc index c3ce8bde3be..1b968b4487d 100644 --- a/docs/src/main/asciidoc/includes/metrics/metrics-shared.adoc +++ b/docs/src/main/asciidoc/includes/metrics/metrics-shared.adoc @@ -37,6 +37,21 @@ endif::[] Metrics is one of the Helidon observability features. +// @Deprecated(forRemoval = true) Remove the following note starting in Helidon 5. +[NOTE] +.Recommended Configuration Setting +==== +Beginning with Helidon 4.1, strongly consider assigning the config setting +[source,properties] +---- +metrics.gc-time-type = gauge +---- +ifdef::mp-flavor[] +so your service complies with the MicroProfile Metrics 5.1 specification. +endif::mp-flavor[] +See the <> in the Configuration section. +==== + // end::overview[] // tag::usage-body[] diff --git a/metrics/api/src/main/java/io/helidon/metrics/api/DistributionSummary.java b/metrics/api/src/main/java/io/helidon/metrics/api/DistributionSummary.java index 74f5c44f94c..33a71aa4e98 100644 --- a/metrics/api/src/main/java/io/helidon/metrics/api/DistributionSummary.java +++ b/metrics/api/src/main/java/io/helidon/metrics/api/DistributionSummary.java @@ -113,6 +113,14 @@ interface Builder extends Meter.Builder { */ Builder distributionStatisticsConfig(DistributionStatisticsConfig.Builder distributionStatisticsConfigBuilder); + /** + * Sets whether to publish a percentile histogram. + * + * @param value true/false + * @return updated builder + */ + Builder publishPercentileHistogram(boolean value); + /** * Returns the scale set on the builder. * @@ -126,5 +134,12 @@ interface Builder extends Meter.Builder { * @return distribution statistics config, if set; empty otherwise */ Optional distributionStatisticsConfig(); + + /** + * Returns whether to publsh percentile histogram. + * + * @return true/false + */ + Optional publishPercentileHistogram(); } } diff --git a/metrics/api/src/main/java/io/helidon/metrics/api/GcTimeType.java b/metrics/api/src/main/java/io/helidon/metrics/api/GcTimeType.java new file mode 100644 index 00000000000..16ffb440792 --- /dev/null +++ b/metrics/api/src/main/java/io/helidon/metrics/api/GcTimeType.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 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.metrics.api; + +/** + * Choices for the meter type for the {@code gc.time} meter. + */ +@Deprecated(since = "4.1", forRemoval = true) +public enum GcTimeType { + /** + * Implement the meter as a gauge. This is backward-incompatible with Helidon 4.0.x releases but complies with + * MicroProfile 5.1. + */ + GAUGE, + + /** + * Implement the meter as a counter. This is backward-compatible with Helidon 4.0.x releases but does not comply with + * MicroProfile 5.1. + */ + COUNTER +} diff --git a/metrics/api/src/main/java/io/helidon/metrics/api/MetricsConfigBlueprint.java b/metrics/api/src/main/java/io/helidon/metrics/api/MetricsConfigBlueprint.java index 6b40aacd41e..dd0dd035788 100644 --- a/metrics/api/src/main/java/io/helidon/metrics/api/MetricsConfigBlueprint.java +++ b/metrics/api/src/main/java/io/helidon/metrics/api/MetricsConfigBlueprint.java @@ -206,6 +206,19 @@ static List createTags(String pairs) { @Option.Redundant Config config(); + /** + * Whether the {@code gc.time} meter should be registered as a gauge (vs. a counter). + * The {@code gc.time} meter is inspired by the MicroProfile Metrics spec, in which the meter was originally checked to + * be a counter but starting in 5.1 was checked be a gauge. For the duration of Helidon 4.x users can choose which + * type of meter Helidon registers for {@code gc.time}. + * @return the type of meter to use for registering {@code gc.time} + * @deprecated Provided for backward compatibility only; no replacement + */ + @Deprecated(since = "4.1", forRemoval = true) + @Option.Configured + @Option.Default("COUNTER") + GcTimeType gcTimeType(); + /** * Reports whether the specified scope is enabled, according to any scope configuration that * is part of this metrics configuration. diff --git a/metrics/api/src/main/java/io/helidon/metrics/api/NoOpMeter.java b/metrics/api/src/main/java/io/helidon/metrics/api/NoOpMeter.java index f0495bd0c05..fb062af5c9b 100644 --- a/metrics/api/src/main/java/io/helidon/metrics/api/NoOpMeter.java +++ b/metrics/api/src/main/java/io/helidon/metrics/api/NoOpMeter.java @@ -354,6 +354,7 @@ static class Builder extends NoOpMeter.Builder private io.helidon.metrics.api.DistributionStatisticsConfig.Builder distributionStatisticsConfigBuilder; private Double scale; + private boolean publishPercentileHistogram; private Builder(String name) { super(name, Type.DISTRIBUTION_SUMMARY); @@ -377,6 +378,12 @@ public Builder distributionStatisticsConfig( return identity(); } + @Override + public io.helidon.metrics.api.DistributionSummary.Builder publishPercentileHistogram(boolean value) { + this.publishPercentileHistogram = value; + return identity(); + } + @Override public Optional scale() { return Optional.ofNullable(scale); @@ -386,6 +393,12 @@ public Optional scale() { public Optional distributionStatisticsConfig() { return Optional.ofNullable(distributionStatisticsConfigBuilder); } + + @Override + public Optional publishPercentileHistogram() { + return Optional.ofNullable(publishPercentileHistogram); + } + } } @@ -628,6 +641,7 @@ static class Builder extends NoOpMeter.Builder implements io.hel private Duration[] buckets; private Duration min; private Duration max; + private Boolean publishPercentileHistogram; private Builder(String name) { super(name, Type.TIMER); @@ -662,6 +676,12 @@ public Builder maximumExpectedValue(Duration max) { return identity(); } + @Override + public io.helidon.metrics.api.Timer.Builder publishPercentileHistogram(boolean value) { + publishPercentileHistogram = value; + return identity(); + } + @Override public Iterable percentiles() { return Arrays.stream(percentiles) @@ -683,6 +703,11 @@ public Optional maximumExpectedValue() { return Optional.ofNullable(max); } + @Override + public Optional publishPercentileHistogram() { + return Optional.ofNullable(publishPercentileHistogram); + } + } } diff --git a/metrics/api/src/main/java/io/helidon/metrics/api/Timer.java b/metrics/api/src/main/java/io/helidon/metrics/api/Timer.java index 38bc30dd31b..1570b1604ea 100644 --- a/metrics/api/src/main/java/io/helidon/metrics/api/Timer.java +++ b/metrics/api/src/main/java/io/helidon/metrics/api/Timer.java @@ -226,6 +226,14 @@ interface Builder extends Meter.Builder { */ Builder maximumExpectedValue(Duration max); + /** + * Prepares the timer to publish a percentile histogram. + * + * @param value whether to publish a percentile histogram + * @return updated builder + */ + Builder publishPercentileHistogram(boolean value); + /** * Returns the percentiles set in the builder, if any. * @@ -253,5 +261,12 @@ interface Builder extends Meter.Builder { * @return maximum expected value if set; empty otherwise */ Optional maximumExpectedValue(); + + /** + * Returns the setting for publishing percentile histogram. + * + * @return whether to publish percentile histogram + */ + Optional publishPercentileHistogram(); } } diff --git a/metrics/api/src/test/java/io/helidon/metrics/api/TestGcTimeTypeChoice.java b/metrics/api/src/test/java/io/helidon/metrics/api/TestGcTimeTypeChoice.java new file mode 100644 index 00000000000..5b788f4b291 --- /dev/null +++ b/metrics/api/src/test/java/io/helidon/metrics/api/TestGcTimeTypeChoice.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024 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.metrics.api; + +import java.util.Map; + +import io.helidon.config.Config; +import io.helidon.config.ConfigMappingException; +import io.helidon.config.ConfigSources; + +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@Deprecated(since = "4.1", forRemoval = true) +class TestGcTimeTypeChoice { + + @Test + void checkDefaultIsCounterForBackwardCompatibility() { + Config config = Config.just(ConfigSources.create(Map.of())); + MetricsConfig metricsConfig = MetricsConfig.create(config); + assertThat("Defaulted gc.time type", metricsConfig.gcTimeType(), is(GcTimeType.COUNTER)); + } + + @Test + void checkExplicitCounter() { + Config config = Config.just(ConfigSources.create(Map.of("gc-time-type", "counter"))); + MetricsConfig metricsConfig = MetricsConfig.create(config); + assertThat("Explicit gc.time type as counter", + metricsConfig.gcTimeType(), + is(GcTimeType.COUNTER)); + } + + @Test + void checkGauge() { + Config config = Config.just(ConfigSources.create(Map.of("gc-time-type", "gauge"))); + MetricsConfig metricsConfig = MetricsConfig.create(config); + assertThat("Explicit gc.time type as gauge", + metricsConfig.gcTimeType(), + is(GcTimeType.GAUGE)); + } + + @Test + void checkInvalidSetting() { + Config config = Config.just(ConfigSources.create(Map.of("gc-time-type", "bad"))); + assertThrows(ConfigMappingException.class, () ->MetricsConfig.create(config)); + } +} diff --git a/metrics/provider-tests/src/main/java/io/helidon/metrics/provider/tests/TestDistributionSummary.java b/metrics/provider-tests/src/main/java/io/helidon/metrics/provider/tests/TestDistributionSummary.java index f9e7ad05a5f..9de795df4d9 100644 --- a/metrics/provider-tests/src/main/java/io/helidon/metrics/provider/tests/TestDistributionSummary.java +++ b/metrics/provider-tests/src/main/java/io/helidon/metrics/provider/tests/TestDistributionSummary.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2024 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. @@ -27,6 +27,10 @@ import io.helidon.metrics.api.Metrics; import io.helidon.metrics.api.ValueAtPercentile; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.Matchers; +import org.hamcrest.TypeSafeMatcher; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -73,13 +77,15 @@ void testPercentiles() { List vaps = list(snapshot.percentileValues()); + // Micrometer allows developers to set the precision with which percentiles are maintained which can give rise to + // some variance in the values reported for the percentiles. assertThat("Values at percentile", vaps, contains( - equalTo(Vap.create(0.50D, 3.0625D)), - equalTo(Vap.create(0.90D, 7.1875D)), - equalTo(Vap.create(0.99D, 7.1875D)), - equalTo(Vap.create(0.999D, 7.1875D)))); + ValueAtPercentileMatcher.matchesWithinTolerance(Vap.create(0.50D, 3.0D), 0.2d), + ValueAtPercentileMatcher.matchesWithinTolerance(Vap.create(0.90D, 7.0D), 0.2d), + ValueAtPercentileMatcher.matchesWithinTolerance(Vap.create(0.99D, 7.0), 0.2d), + ValueAtPercentileMatcher.matchesWithinTolerance(Vap.create(0.999D, 7.0), 0.2d))); } @Test @@ -143,6 +149,37 @@ private static ValueAtPercentile create(double percentile, double value) { } } + /** + * Hamcrest matcher for a ValueAtPercentile that checks the percentile setting and the value recorded for that percentile. + */ + private static class ValueAtPercentileMatcher extends TypeSafeMatcher { + + static ValueAtPercentileMatcher matchesWithinTolerance(ValueAtPercentile expected, double variance) { + return new ValueAtPercentileMatcher(expected, variance); + } + + private final ValueAtPercentile expected; + private final Matcher valueWithinToleranceMatcher; + + private ValueAtPercentileMatcher(ValueAtPercentile expected, double variance) { + valueWithinToleranceMatcher = Matchers.closeTo(expected.value(), variance); + this.expected = expected; + } + + @Override + protected boolean matchesSafely(ValueAtPercentile item) { + return item.percentile() == expected.percentile() + && valueWithinToleranceMatcher.matches(item.value()); + } + + @Override + public void describeTo(Description description) { + description.appendText("percentile expected to be " + expected.percentile() + + " and "); + valueWithinToleranceMatcher.describeTo(description); + } + } + private record Cab(double boundary, long count) implements Bucket { @Override diff --git a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MDistributionStatisticsConfig.java b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MDistributionStatisticsConfig.java index 3c385fc90d1..5a8a37b925e 100644 --- a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MDistributionStatisticsConfig.java +++ b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MDistributionStatisticsConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2024 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. @@ -21,11 +21,25 @@ import io.helidon.metrics.api.DistributionStatisticsConfig; -import io.micrometer.core.instrument.distribution.DistributionStatisticConfig; - +import io.micrometer.core.instrument.DistributionSummary; + +/** + * Statistics config implementation for the Micrometer metrics provider. + *

+ * Most of our implementation classes have a delegate which points to the corresponding Micrometer instance. Although + * Micrometer does have a {@link io.micrometer.core.instrument.distribution.DistributionStatisticConfig} type it is + * hidden inside the {@link io.micrometer.core.instrument.DistributionSummary} and we cannot access it. + *

+ * As a result, this class does not have a delegate. To satisfy the Helidon metrics API this type keeps a copy of the + * relevant information that is also stored in its Micrometer counterpart. + *

+ */ class MDistributionStatisticsConfig implements io.helidon.metrics.api.DistributionStatisticsConfig { - private final DistributionStatisticConfig delegate; + private final double[] percentiles; + private final double[] buckets; + private final Optional minimumExpectedValue; + private final Optional maximumExpectedValue; /** * Creates a new config instance from a builder (which wraps a Micrometer config builder). @@ -33,20 +47,14 @@ class MDistributionStatisticsConfig implements io.helidon.metrics.api.Distributi * @param builder builder which wraps the Micrometer config builder */ private MDistributionStatisticsConfig(Builder builder) { - delegate = builder.delegate.build(); - } - - /** - * Creates a new config instance, primarily from a merge operation. - * - * @param delegate pre-existing delegate - */ - private MDistributionStatisticsConfig(DistributionStatisticConfig delegate) { - this.delegate = delegate; + percentiles = builder.percentiles; + buckets = builder.buckets; + minimumExpectedValue = builder.minimumExpectedValue(); + maximumExpectedValue = builder.maximumExpectedValue(); } - static Builder builder() { - return new Builder(); + static Builder builder(DistributionSummary.Builder micrometerSummaryBuilder) { + return new Builder(micrometerSummaryBuilder); } static T chooseOpt(T fromChild, Supplier> fromParent) { @@ -54,8 +62,9 @@ static T chooseOpt(T fromChild, Supplier> fromParent) { () -> fromParent.get().orElse(null)); } - static MDistributionStatisticsConfig.Builder builderFrom(DistributionStatisticsConfig.Builder other) { - MDistributionStatisticsConfig.Builder configBuilder = MDistributionStatisticsConfig.builder(); + static MDistributionStatisticsConfig.Builder builderFrom(MDistributionSummary.Builder sBuilder, + DistributionStatisticsConfig.Builder other) { + MDistributionStatisticsConfig.Builder configBuilder = MDistributionStatisticsConfig.builder(sBuilder.delegate()); configBuilder.from(other); return configBuilder; } @@ -63,52 +72,61 @@ static MDistributionStatisticsConfig.Builder builderFrom(DistributionStatisticsC @Override public Optional> percentiles() { - return Optional.ofNullable(Util.iterable(delegate.getPercentiles())); + return Optional.ofNullable(Util.iterable(percentiles)); } @Override public Optional minimumExpectedValue() { - return Optional.ofNullable(delegate.getMinimumExpectedValueAsDouble()); + return minimumExpectedValue; } @Override public Optional maximumExpectedValue() { - return Optional.ofNullable(delegate.getMaximumExpectedValueAsDouble()); + return maximumExpectedValue; } @Override public Optional> buckets() { - return Optional.ofNullable(Util.iterable(delegate.getServiceLevelObjectiveBoundaries())); + return Optional.ofNullable(Util.iterable(buckets)); } @Override public R unwrap(Class c) { - return c.cast(delegate); - } - - io.micrometer.core.instrument.distribution.DistributionStatisticConfig delegate() { - return delegate; + throw new IllegalArgumentException(getClass().getSimpleName() + " does not have a delegate to unwrap"); } + /** + * Builder for the {@link }{@link io.helidon.metrics.api.DistributionStatisticsConfig}} in the Micrometer provider. + *

+ * Although Micrometer uses its own stats config builder internally it is not accessible to us. Instead, for example to + * set the percentiles in the Micrometer stats config builder, we invoke a method on the Micrometer + * {}@link {@link io.micrometer.core.instrument.DistributionSummary.Builder}, and it delegates to its internal stats + * builder. + *

+ * Therefore, the "delegate" for this builder is the builder for the Micrometer DistributionSummary. Further, because + * the Micrometer DistributionSummary.Builder does not expose the stats config values that have been set in its internal + * stats config builder, our implementation has to record those values itself. + *

+ */ static class Builder implements io.helidon.metrics.api.DistributionStatisticsConfig.Builder { static final double[] DEFAULT_PERCENTILES = {0.5, 0.75, 0.95, 0.98, 0.99, 0.999}; static final int DEFAULT_PRECISION = 3; - private final DistributionStatisticConfig.Builder delegate; + private final DistributionSummary.Builder delegate; private Optional min = Optional.empty(); private Optional max = Optional.empty(); - private double[] percentiles; + private double[] percentiles = DEFAULT_PERCENTILES; private double[] buckets; - private Builder() { - delegate = DistributionStatisticConfig.builder(); - percentiles(DEFAULT_PERCENTILES); + private Builder(DistributionSummary.Builder delegate) { + this.delegate = delegate; + delegate.percentilePrecision(DEFAULT_PRECISION); + delegate.publishPercentiles(DEFAULT_PERCENTILES); } @Override public MDistributionStatisticsConfig build() { - delegate.percentilePrecision(DEFAULT_PRECISION); return new MDistributionStatisticsConfig(this); } @@ -129,14 +147,14 @@ public Builder maximumExpectedValue(Double max) { @Override public Builder percentiles(double... percentiles) { this.percentiles = percentiles; - delegate.percentiles(percentiles); + delegate.publishPercentiles(percentiles); return this; } @Override public Builder percentiles(Iterable percentiles) { this.percentiles = Util.doubleArray(percentiles); - delegate.percentiles(this.percentiles); + delegate.publishPercentiles(this.percentiles); return this; } @@ -176,11 +194,13 @@ public Iterable buckets() { @Override public R unwrap(Class c) { - return c.cast(delegate); - } - - DistributionStatisticConfig.Builder delegate() { - return delegate; + if (c.isInstance(delegate)) { + return c.cast(delegate); + } + if (c.isInstance(this)) { + return c.cast(this); + } + throw new IllegalArgumentException("Cannot unwrap to " + c.getName()); } public Builder from(DistributionStatisticsConfig.Builder other) { @@ -191,4 +211,131 @@ public Builder from(DistributionStatisticsConfig.Builder other) { return this; } } + + /** + * Implementation of {@link io.helidon.metrics.api.DistributionStatisticsConfig} for Micrometer with no related + * {@link io.micrometer.core.instrument.DistributionSummary}. + *

+ * In some cases, our wrapper around the Micrometer + * {@link io.micrometer.core.instrument.distribution.DistributionStatisticConfig} will not have a delegate which points + * to a related {@link io.micrometer.core.instrument.DistributionSummary}. This class handles that case. + *

+ */ + static class Unconnected implements DistributionStatisticsConfig { + private Optional min = Optional.empty(); + private Optional max = Optional.empty(); + private double[] percentiles; + private double[] buckets; + + + static Builder builder() { + return new Builder(); + } + + private Unconnected(DistributionStatisticsConfig.Builder builder) { + min = builder.minimumExpectedValue(); + max = builder.maximumExpectedValue(); + percentiles = Util.doubleArray(builder.percentiles()); + buckets = Util.doubleArray(builder.buckets()); + } + + @Override + public Optional> percentiles() { + return Optional.ofNullable(Util.iterable(percentiles)); + } + + @Override + public Optional minimumExpectedValue() { + return min; + } + + @Override + public Optional maximumExpectedValue() { + return max; + } + + @Override + public Optional> buckets() { + return Optional.ofNullable(Util.iterable(buckets)); + } + + @Override + public R unwrap(Class c) { + return c.cast(this); + } + + static class Builder implements DistributionStatisticsConfig.Builder { + + private Optional min = Optional.empty(); + private Optional max = Optional.empty(); + private double[] percentiles = MDistributionStatisticsConfig.Builder.DEFAULT_PERCENTILES; + private double[] buckets; + + @Override + public DistributionStatisticsConfig.Builder minimumExpectedValue(Double min) { + this.min = Optional.of(min); + return identity(); + } + + @Override + public DistributionStatisticsConfig.Builder maximumExpectedValue(Double max) { + this.max = Optional.of(max); + return identity(); + } + + @Override + public DistributionStatisticsConfig.Builder percentiles(double... percentiles) { + this.percentiles = percentiles; + return identity(); + } + + @Override + public DistributionStatisticsConfig.Builder percentiles(Iterable percentiles) { + this.percentiles = Util.doubleArray(percentiles); + return identity(); + } + + @Override + public DistributionStatisticsConfig.Builder buckets(double... buckets) { + this.buckets = buckets; + return identity(); + } + + @Override + public DistributionStatisticsConfig.Builder buckets(Iterable buckets) { + this.buckets = Util.doubleArray(buckets); + return identity(); + } + + @Override + public Optional minimumExpectedValue() { + return min; + } + + @Override + public Optional maximumExpectedValue() { + return max; + } + + @Override + public Iterable percentiles() { + return Util.iterable(percentiles); + } + + @Override + public Iterable buckets() { + return Util.iterable(buckets); + } + + @Override + public DistributionStatisticsConfig build() { + return new Unconnected(this); + } + + @Override + public R unwrap(Class c) { + return c.cast(this); + } + } + } } diff --git a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MDistributionSummary.java b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MDistributionSummary.java index 10661580960..99f04b429ae 100644 --- a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MDistributionSummary.java +++ b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MDistributionSummary.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2024 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. @@ -50,14 +50,20 @@ static Builder builder(String name, return new Builder(name, configBuilder); } + static Builder builder(String name) { + return new Builder(name); + } + static Builder builderFrom(DistributionSummary.Builder sBuilder) { + + MDistributionSummary.Builder b = MDistributionSummary.builder(sBuilder.name()); MDistributionStatisticsConfig.Builder configBuilder = sBuilder.distributionStatisticsConfig().isPresent() - ? MDistributionStatisticsConfig.builder() - : MDistributionStatisticsConfig.builderFrom(sBuilder.distributionStatisticsConfig().get()); + ? MDistributionStatisticsConfig.builder(b.delegate()) + : MDistributionStatisticsConfig.builderFrom(b, sBuilder.distributionStatisticsConfig().get()); - MDistributionSummary.Builder b = MDistributionSummary.builder(sBuilder.name(), configBuilder); - b.from(sBuilder); + b.distributionStatisticsConfig(configBuilder) + .from(sBuilder); return b; } @@ -121,23 +127,30 @@ static class Builder extends private Double scale; private DistributionStatisticsConfig.Builder distributionStatisticsConfigBuilder; + private Boolean publishPercentileHistogram; private Builder(String name, DistributionStatisticsConfig.Builder configBuilder) { this(name, configBuilder.build()); } private Builder(String name, DistributionStatisticsConfig config) { - super(name, io.micrometer.core.instrument.DistributionSummary.builder(name) - .publishPercentiles(config.percentiles() + this(name); + distributionStatisticsConfigBuilder + .percentiles(config.percentiles() .map(Util::doubleArray) .orElse(DEFAULT.getPercentiles())) - .serviceLevelObjectives(config.buckets() + .buckets(config.buckets() .map(Util::doubleArray) .orElse(DEFAULT.getServiceLevelObjectiveBoundaries())) .minimumExpectedValue(config.minimumExpectedValue() .orElse(DEFAULT.getMinimumExpectedValueAsDouble())) .maximumExpectedValue(config.maximumExpectedValue() - .orElse(DEFAULT.getMaximumExpectedValueAsDouble()))); + .orElse(DEFAULT.getMaximumExpectedValueAsDouble())); + } + + private Builder(String name) { + super(name, io.micrometer.core.instrument.DistributionSummary.builder(name)); + distributionStatisticsConfigBuilder = MDistributionStatisticsConfig.builder(delegate()); } @Override @@ -191,6 +204,13 @@ protected Builder delegateBaseUnit(String baseUnit) { return identity(); } + @Override + public DistributionSummary.Builder publishPercentileHistogram(boolean value) { + delegate().publishPercentileHistogram(value); + publishPercentileHistogram = value; + return identity(); + } + @Override public Optional scale() { return Optional.ofNullable(scale); @@ -201,6 +221,11 @@ public Optional distributionStatisticsConf return Optional.ofNullable(distributionStatisticsConfigBuilder); } + @Override + public Optional publishPercentileHistogram() { + return Optional.ofNullable(publishPercentileHistogram); + } + protected Builder from(DistributionSummary.Builder other) { other.scale().ifPresent(this::scale); return this; diff --git a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MTimer.java b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MTimer.java index ed6ab3d9eda..6b9141f5f6d 100644 --- a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MTimer.java +++ b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MTimer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2024 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. @@ -195,6 +195,7 @@ static class Builder extends private Duration[] buckets; private Duration min; private Duration max; + private Boolean publishPercentileHistogram; private Builder(String name) { super(name, io.micrometer.core.instrument.Timer.builder(name)); @@ -253,6 +254,12 @@ protected Builder delegateBaseUnit(String baseUnit) { return identity(); } + @Override + public Builder publishPercentileHistogram(boolean value) { + delegate().publishPercentileHistogram(value); + return identity(); + } + @Override public Iterable percentiles() { return Util.iterable(percentiles); @@ -273,6 +280,11 @@ public Optional maximumExpectedValue() { return Optional.ofNullable(max); } + @Override + public Optional publishPercentileHistogram() { + return Optional.ofNullable(publishPercentileHistogram); + } + @Override protected MTimer build(Meter.Id id, io.micrometer.core.instrument.Timer meter) { return new MTimer(id, meter, this); diff --git a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MicrometerMetricsFactory.java b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MicrometerMetricsFactory.java index bed563d9775..241af47bb29 100644 --- a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MicrometerMetricsFactory.java +++ b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MicrometerMetricsFactory.java @@ -248,7 +248,7 @@ public FunctionalCounter.Builder functionalCounterBuilder(String name, @Override public DistributionStatisticsConfig.Builder distributionStatisticsConfigBuilder() { - return MDistributionStatisticsConfig.builder(); + return MDistributionStatisticsConfig.Unconnected.builder(); } @Override diff --git a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MicrometerPrometheusFormatter.java b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MicrometerPrometheusFormatter.java index c8aa27050fb..b93a1db94be 100644 --- a/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MicrometerPrometheusFormatter.java +++ b/metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MicrometerPrometheusFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2024 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. @@ -106,7 +106,7 @@ public static String normalizeNameToPrometheus(String name) { static Set meterNameSuffixes(Meter.Type meterType) { return switch (meterType) { case COUNTER -> Set.of("_total"); - case DISTRIBUTION_SUMMARY, LONG_TASK_TIMER, TIMER -> Set.of("_count", "_sum", "_max"); + case DISTRIBUTION_SUMMARY, LONG_TASK_TIMER, TIMER -> Set.of("_count", "_sum", "_max", "_bucket"); case GAUGE, OTHER -> Set.of(); }; } diff --git a/metrics/system-meters/src/main/java/io/helidon/metrics/systemmeters/SystemMetersProvider.java b/metrics/system-meters/src/main/java/io/helidon/metrics/systemmeters/SystemMetersProvider.java index 8b8d13d85bf..9f70e7bfc01 100644 --- a/metrics/system-meters/src/main/java/io/helidon/metrics/systemmeters/SystemMetersProvider.java +++ b/metrics/system-meters/src/main/java/io/helidon/metrics/systemmeters/SystemMetersProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2024 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. @@ -240,11 +240,21 @@ private static Function typedFn(Function ge GarbageCollectorMXBean::getCollectionCount, Tag.create("name", poolName)); // Express the GC time in seconds. - registerFunctionalCounter(result, - GC_TIME, - gcBean, - bean -> (long) (bean.getCollectionTime() / 1000.0D), - Tag.create("name", poolName)); + // @Deprecated(forRemoval = true) - Starting in Helidon 5 always register a gauge instead of checking which + // type of meter to register. + if (isGcTimeGauge()) { + registerGauge(result, + GC_TIME, + gcBean, + bean -> (long) (bean.getCollectionTime() / 1000.0D), + Tag.create("name", poolName)); + } else { + registerFunctionalCounter(result, + GC_TIME, + gcBean, + bean -> (long) (bean.getCollectionTime() / 1000.0D), + Tag.create("name", poolName)); + } } return result; } @@ -273,6 +283,12 @@ private void registerFunctionalCounter(Collection> resul .tags(Arrays.asList(tags))); } + @Deprecated(since = "4.1", forRemoval = true) + private boolean isGcTimeGauge() { + // Compare using the string so we can avoid exposing the temporary, deprecated enum as public in the config type. + return metricsFactory.metricsConfig().gcTimeType().name().equals("GAUGE"); + } + private static class Metadata { private final String name; diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/DistributionCustomizations.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/DistributionCustomizations.java new file mode 100644 index 00000000000..4b171e2ad42 --- /dev/null +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/DistributionCustomizations.java @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2024 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.microprofile.metrics; + +import java.lang.reflect.Array; +import java.time.Duration; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; +import java.util.function.Function; + +import io.helidon.common.Errors; +import io.helidon.common.LazyValue; +import io.helidon.metrics.api.DistributionStatisticsConfig; +import io.helidon.metrics.api.DistributionSummary; +import io.helidon.metrics.api.Timer; + +import org.eclipse.microprofile.config.Config; + +/** + * Internal logic for handling config-based customization of percentiles and buckets. + *

+ * MicroProfile Metrics 5.1 permits users to configure percentile and bucket settings for timers and histograms in + * {@code META-INF/microprofile-config.properties}. This class encapsulates the processing to apply those defaults. + *

+ * The general format of the config value is a semicolon-separated list of {@code nameExpression=values} + * where each {@code values} is a comma-separated list of values. The {@code nameExpression} can be: + *

    + *
  • exact metric name
  • + *
  • metric name prefix followed by {@code *}
  • + *
  • {@code *}
  • + *
  • nothing.
  • + *
+ *

+ * Further, Micrometer provides a default set of histogram buckets which users can choose to apply to meters following the + * same {@code nameExpression} pattern. + *

+ *

+ */ +class DistributionCustomizations { + + private static final System.Logger LOGGER = System.getLogger(DistributionCustomizations.class.getName()); + + private static final double DEFAULT_SUMMARY_MIN = 0.05d; + private static final double DEFAULT_SUMMARY_MAX = 10000d; + private static final Duration DEFAULT_TIMER_MIN = Duration.ofMillis(5); + private static final Duration DEFAULT_TIMER_MAX = Duration.ofSeconds(10); + + private static DistributionCustomizations instance; + private final List percentileCustomizations; + private final List summaryBucketCustomizations; + private final List timerBucketCustomizations; + private final List> summaryBucketDefaultCustomizations; + + private DistributionCustomizations(Config mpConfig) { + + percentileCustomizations = collect(mpConfig, "mp.metrics.distribution.percentiles", Percentiles::new); + + summaryBucketCustomizations = collect(mpConfig, "mp.metrics.distribution.histogram.buckets", SummaryBuckets::new); + + timerBucketCustomizations = collect(mpConfig, "mp.metrics.distribution.timer.buckets", TimerBuckets::new); + + summaryBucketDefaultCustomizations = collect(mpConfig, + "mp.metrics.distribution.percentiles-histogram.enabled", + expression -> new SingleValuedCustomization<>(expression, + Boolean::parseBoolean)); + } + + static void init(Config mpConfig) { + instance = new DistributionCustomizations(mpConfig); + } + + static DistributionSummary.Builder apply(DistributionSummary.Builder builder) { + DistributionStatisticsConfig.Builder statsBuilder = builder.distributionStatisticsConfig() + .orElseGet(() -> { + DistributionStatisticsConfig.Builder newBuilder = DistributionStatisticsConfig.builder(); + builder.distributionStatisticsConfig(newBuilder); + return newBuilder; + }); + instance.percentileCustomizations.stream() + .filter(p -> p.matches(builder.name())) + .forEach(p -> statsBuilder.percentiles(p.percentiles())); + + AtomicBoolean matched = new AtomicBoolean(); + instance.summaryBucketCustomizations.stream() + .filter(b -> b.matches(builder.name())) + .forEach(b -> { + matched.set(true); + statsBuilder.buckets(b.buckets()); + }); + + if (!matched.get()) { + instance.summaryBucketDefaultCustomizations.stream() + .filter(def -> def.matches(builder.name())) + .map(SingleValuedCustomization::value) + .reduce((a, b) -> b) // Always take the latest match. + .ifPresent(def -> { + builder.publishPercentileHistogram(def); + statsBuilder.minimumExpectedValue(DEFAULT_SUMMARY_MIN) + .maximumExpectedValue(DEFAULT_SUMMARY_MAX); + + }); + } + + return builder; + } + + static Timer.Builder apply(Timer.Builder builder) { + instance.percentileCustomizations.stream() + .filter(p -> p.matches(builder.name())) + .forEach(p -> builder.percentiles(p.percentiles())); + + AtomicBoolean matched = new AtomicBoolean(); + instance.timerBucketCustomizations.stream() + .filter(b -> b.matches(builder.name())) + .forEach(b -> { + matched.set(true); + builder.buckets(b.buckets()); + }); + + if (!matched.get()) { + instance.summaryBucketDefaultCustomizations.stream() + .filter(def -> def.matches(builder.name())) + .map(SingleValuedCustomization::value) + .reduce((a, b) -> b) // Always take the latest match. + .ifPresent(def -> { + builder.publishPercentileHistogram(def); + builder.minimumExpectedValue(DEFAULT_TIMER_MIN) + .maximumExpectedValue(DEFAULT_TIMER_MAX); + }); + } + + return builder; + } + + private static List collect(Config mpConfig, + String configKey, + Function factory) { + return mpConfig.getOptionalValue(configKey, String.class) + .stream() + .flatMap(s -> Arrays.stream(s.split(";"))) + .map(factory) + .toList(); + } + + private static double[] doubles(Double[] doubles) { + double[] result = new double[doubles.length]; + for (int i = 0; i < doubles.length; i++) { + result[i] = doubles[i]; + } + return result; + } + + abstract static class Customization { + private final String namePrefix; + private final boolean hasTrailingWildcard; + private final String valuesExpression; + + protected Customization(String nameExpressionAndValues) { + int eq = nameExpressionAndValues.indexOf('='); + if (eq <= 0) { + valuesExpression = ""; + namePrefix = ""; + hasTrailingWildcard = false; + return; + } + String namePrefixMaybeWithWildcard = nameExpressionAndValues.substring(0, eq); + hasTrailingWildcard = namePrefixMaybeWithWildcard.endsWith("*"); + namePrefix = namePrefixMaybeWithWildcard.substring(0, hasTrailingWildcard ? eq - 1 : eq); + valuesExpression = nameExpressionAndValues.substring(eq + 1); + } + + protected String namePrefix() { + return namePrefix; + } + + protected boolean hasTrailingWildcard() { + return hasTrailingWildcard; + } + + protected String valuesExpression() { + return valuesExpression; + } + + protected boolean matches(String metricName) { + return hasTrailingWildcard() ? metricName.startsWith(namePrefix()) + : metricName.equals(namePrefix()); + } + } + + static class SingleValuedCustomization extends Customization { + + private final T value; + + protected SingleValuedCustomization(String nameAndValuesExpression, Function valueParser) { + super(nameAndValuesExpression); + value = valueParser.apply(valuesExpression()); + } + + protected T value() { + return value; + } + } + + abstract static class MultiValuedCustomization> extends Customization { + + private final T[] values; + + protected MultiValuedCustomization(String nameExpressionAndValues, + Class type, + Function valueParser, + Consumer valueChecker) { + super(nameExpressionAndValues); + if (valuesExpression().isBlank()) { + values = (T[]) Array.newInstance(type, 0); + return; + } + values = values(valuesExpression(), type, valueParser, valueChecker); + } + + protected T[] values() { + return values; + } + + private T[] values(String valuesString, + Class type, + Function valueParser, + Consumer valueChecker) { + String[] valueStrings = valuesString.split(","); + T[] result = (T[]) Array.newInstance(type, valueStrings.length); + int next = 0; + T prev = null; + boolean valuesInOrder = true; + LazyValue collector = LazyValue.create(Errors::collector); + for (String valueString : valueStrings) { + if (!valueString.isBlank()) { + T value; + try { + value = valueParser.apply(valueString); + } catch (Exception ex) { + // The spec says to ignore invalid values but we'll warn about it. + collector.get().warn("ignoring invalid value: " + ex.getMessage()); + continue; + } + valuesInOrder &= prev != null && prev.compareTo(value) < 0; + try { + valueChecker.accept(value); + } catch (Exception ex) { + collector.get().warn("ignoring value for " + + namePrefix() + + (hasTrailingWildcard() ? "*" : ": ") + + ex.getMessage()); + continue; + } + result[next++] = value; + prev = value; + } + } + if (!valuesInOrder) { + collector.get().warn("Values for " + + namePrefix() + + (hasTrailingWildcard() ? "*" : "") + + "should be in strictly increasing order but are not: " + + Arrays.toString(valueStrings)); + } + + if (collector.isLoaded()) { + collector.get().collect().log(LOGGER); + } + return Arrays.copyOf(result, next); + } + } + + static class Percentiles extends MultiValuedCustomization { + + private final double[] values; + + private Percentiles(String nameExpressionAndValues) { + super(nameExpressionAndValues, Double.class, Double::parseDouble, d -> { + if (d < 0.0d || d > 1.0d) { + throw new IllegalArgumentException("Value " + d + " not in required range [0.0, 1.0]"); + } + }); + values = doubles(values()); + } + + double[] percentiles() { + return values; + } + } + + static class SummaryBuckets extends MultiValuedCustomization { + + private final double[] values; + + private SummaryBuckets(String nameExpressionAndValues) { + super(nameExpressionAndValues, Double.class, Double::parseDouble, d -> { + if (d <= 0) { + throw new IllegalArgumentException("Value must be > 0 but " + d + " is not"); + } + }); + values = doubles(values()); + } + + double[] buckets() { + return values; + } + } + + static class TimerBuckets extends MultiValuedCustomization { + + private TimerBuckets(String nameExpressionAndValues) { + super(nameExpressionAndValues, Duration.class, TimerBuckets::parseTimerBucketExpression, d -> { + }); + } + + protected Duration[] buckets() { + return values(); + } + + private static Duration parseTimerBucketExpression(String expr) { + TimeUnit timeUnit; + int suffixSize = 1; + String lcExpr = expr.toLowerCase(Locale.ROOT); + if (lcExpr.endsWith("ms")) { + timeUnit = TimeUnit.MILLISECONDS; + suffixSize = 2; + } else if (lcExpr.endsWith("s")) { + timeUnit = TimeUnit.SECONDS; + } else if (lcExpr.endsWith("m")) { + timeUnit = TimeUnit.MINUTES; + } else if (lcExpr.endsWith("h")) { + timeUnit = TimeUnit.HOURS; + } else { + timeUnit = TimeUnit.MILLISECONDS; + suffixSize = 0; + } + int amount = Integer.parseInt(expr.substring(0, expr.length() - suffixSize)); + return Duration.of(amount, timeUnit.toChronoUnit()); + } + } + +} diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/HelidonHistogram.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/HelidonHistogram.java index c21b47cf9d2..5a38d4adb0f 100644 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/HelidonHistogram.java +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/HelidonHistogram.java @@ -42,11 +42,12 @@ private HelidonHistogram(String scope, Metadata metadata, DistributionSummary de static HelidonHistogram create(MeterRegistry meterRegistry, String scope, Metadata metadata, Tag... tags) { return create(scope, metadata, - meterRegistry.getOrCreate(DistributionSummary.builder(metadata.getName()) - .scope(scope) - .description(metadata.getDescription()) - .baseUnit(sanitizeUnit(metadata.getUnit())) - .tags(allTags(scope, tags)))); + meterRegistry.getOrCreate(DistributionCustomizations + .apply(DistributionSummary.builder(metadata.getName()) + .scope(scope) + .description(metadata.getDescription()) + .baseUnit(sanitizeUnit(metadata.getUnit())) + .tags(allTags(scope, tags))))); } static HelidonHistogram create(String scope, diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/HelidonSnapshot.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/HelidonSnapshot.java index 7c9a4e01d5f..765647560d9 100644 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/HelidonSnapshot.java +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/HelidonSnapshot.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2024 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. @@ -67,6 +67,13 @@ public PercentileValue[] percentileValues() { .toArray(PercentileValue[]::new); } + @Override + public HistogramBucket[] bucketValues() { + return StreamSupport.stream(delegate.histogramCounts().spliterator(), false) + .map(bucket -> new HistogramBucket(bucket.boundary(), (long) bucket.count())) + .toArray(HistogramBucket[]::new); + } + @Override public void dump(OutputStream output) { delegate.outputSummary(new PrintStream(output, false, Charset.defaultCharset()), 1); diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/HelidonTimer.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/HelidonTimer.java index 1693937bd1a..667cc766b36 100644 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/HelidonTimer.java +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/HelidonTimer.java @@ -51,10 +51,11 @@ static HelidonTimer create(MeterRegistry meterRegistry, String scope, Metadata m return create(meterRegistry, scope, metadata, - meterRegistry.getOrCreate(io.helidon.metrics.api.Timer.builder(metadata.getName()) - .description(metadata.getDescription()) - .baseUnit(sanitizeUnit(metadata.getUnit())) - .tags(allTags(scope, tags)))); + meterRegistry.getOrCreate(DistributionCustomizations + .apply(io.helidon.metrics.api.Timer.builder(metadata.getName()) + .description(metadata.getDescription()) + .baseUnit(sanitizeUnit(metadata.getUnit())) + .tags(allTags(scope, tags))))); } static HelidonTimer create(MeterRegistry meterRegistry, diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricsCdiExtension.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricsCdiExtension.java index 2c40ce15eca..64ab36bae81 100644 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricsCdiExtension.java +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/MetricsCdiExtension.java @@ -317,7 +317,7 @@ public void registerService(@Observes @Priority(LIBRARY_BEFORE + 10) @Initialize throw new DeploymentException("Metrics module found issues with deployment: " + problems); } - // this needs to be done early on, so the registry is configured before accessed + // this needs to be done early on, so the registry is configured before accessed MetricsObserver observer = configure(); registerMetricsForAnnotatedSites(); @@ -424,15 +424,25 @@ boolean restEndpointsMetricsEnabled() { protected Config componentConfig() { // Combine the Helidon-specific "metrics.xxx" settings with the MP // "mp.metrics.xxx" settings into a single metrics config object. - Config rootConfig = rootConfig(); + org.eclipse.microprofile.config.Config mpConfig = ConfigProvider.getConfig(); + DistributionCustomizations.init(mpConfig); + + /* + Some MP config refers to "mp.metrics.xxx" whereas te neutral SE metrics implementation uses "metrics.yyy" (where + sometimes xxx and yyy are different). In particular, there's "mp.metrics.appName" -> "metrics.app-name" + + The next section maps MP config settings (if present) to the corresponding SE config settings, possibly adjusting the + key name in the process. + */ + Map mpToSeKeyNameMap = Map.of("appName", "app-name"); Map mpConfigSettings = new HashMap<>(); - Stream.of("tags", "appName") - .forEach(key -> { - rootConfig.get("mp.metrics." + key) - .asString() - .ifPresent(value -> mpConfigSettings.put(key, value)); - }); + Stream.of("tags", + "appName") + .forEach(key -> + mpConfig.getOptionalValue("mp.metrics." + key, String.class) + .ifPresent(value -> mpConfigSettings.put(mpToSeKeyNameMap.getOrDefault(key, key), + value))); Config metricsConfig = super.componentConfig().detach(); diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/Registry.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/Registry.java index c8ff5bb32f6..3f3636781e0 100644 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/Registry.java +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/Registry.java @@ -405,7 +405,7 @@ HelidonMetric onMeterAdded(Meter meter) { Errors.Collector collector = Errors.collector(); - MetricID newMetricID = metricIDWithoutSystemTags(collector, meter.id()); + MetricID newMetricID = metricIDWithoutSystemTags(meter.id()); lock.lock(); @@ -659,7 +659,7 @@ private HelidonHistogram createHistogram(Metadata metadata, Tag... tags) { } private HelidonHistogram createHistogram(io.helidon.metrics.api.DistributionSummary.Builder sBuilder) { - return createMeter(sBuilder, HelidonHistogram::create); + return createMeter(DistributionCustomizations.apply(sBuilder), HelidonHistogram::create); } private HelidonTimer createTimer(Metadata metadata, Tag... tags) { @@ -671,7 +671,7 @@ private HelidonTimer createTimer(Metadata metadata, Tag... tags) { } private HelidonTimer createTimer(io.helidon.metrics.api.Timer.Builder tBuilder) { - return createMeter(tBuilder, d -> HelidonTimer.create(meterRegistry, d)); + return createMeter(DistributionCustomizations.apply(tBuilder), d -> HelidonTimer.create(meterRegistry, d)); } private , @@ -741,6 +741,11 @@ private MetricID metricIDWithoutSystemTags(Errors.Collector collector, Meter.Id return new MetricID(meterId.name(), tags(tagsWithoutScope)); } + private MetricID metricIDWithoutSystemTags(Meter.Id meterId) { + Map tagsWithoutScope = tagsWithoutSystemOrScopeTags(meterId.tags()); + return new MetricID(meterId.name(), tags(tagsWithoutScope)); + } + static class InfoPerName { private final Metadata metadata; diff --git a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/RegistryProducer.java b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/RegistryProducer.java index b69c8f19f21..cbf52441fe3 100644 --- a/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/RegistryProducer.java +++ b/microprofile/metrics/src/main/java/io/helidon/microprofile/metrics/RegistryProducer.java @@ -22,7 +22,6 @@ import jakarta.enterprise.inject.spi.Annotated; import jakarta.enterprise.inject.spi.InjectionPoint; import org.eclipse.microprofile.metrics.MetricRegistry; -import org.eclipse.microprofile.metrics.MetricRegistry.Type; import org.eclipse.microprofile.metrics.annotation.RegistryScope; import org.eclipse.microprofile.metrics.annotation.RegistryType; @@ -40,6 +39,7 @@ private RegistryProducer() { @Produces @Default + @RegistryScope public static org.eclipse.microprofile.metrics.MetricRegistry getScopedRegistry(InjectionPoint injectionPoint) { Annotated annotated = (injectionPoint == null) ? null : injectionPoint.getAnnotated(); RegistryScope scope = (annotated == null) ? null : annotated.getAnnotation(RegistryScope.class); @@ -52,23 +52,23 @@ public static org.eclipse.microprofile.metrics.MetricRegistry getDefaultRegistry return getApplicationRegistry(); } - // TODO Once RegistryScope becomes a qualifier, use it instead of RegistryType. + // TODO Remove if MP Metrics ever removes @RegistryType. @Produces - @RegistryType(type = Type.APPLICATION) + @RegistryType(type = MetricRegistry.Type.APPLICATION) public static org.eclipse.microprofile.metrics.MetricRegistry getApplicationRegistry() { return RegistryFactory.getInstance().getRegistry(MetricRegistry.APPLICATION_SCOPE); } + // TODO Remove if MP Metrics ever removes @RegistryType. @Produces - // TODO Once RegistryScope becomes a qualifier, use it instead of RegistryType. - @RegistryType(type = Type.BASE) + @RegistryType(type = MetricRegistry.Type.BASE) public static org.eclipse.microprofile.metrics.MetricRegistry getBaseRegistry() { return RegistryFactory.getInstance().getRegistry(MetricRegistry.BASE_SCOPE); } - // TODO Once RegistryScope becomes a qualifier, use it instead of RegistryType. + // TODO Remove if MP Metrics ever removes @RegistryType. @Produces - @RegistryType(type = Type.VENDOR) + @RegistryType(type = MetricRegistry.Type.VENDOR) public static org.eclipse.microprofile.metrics.MetricRegistry getVendorRegistry() { return RegistryFactory.getInstance().getRegistry(MetricRegistry.VENDOR_SCOPE); } diff --git a/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/HelloWorldAsyncResponseTest.java b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/HelloWorldAsyncResponseTest.java index 2b092a5d482..d23764ad5eb 100644 --- a/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/HelloWorldAsyncResponseTest.java +++ b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/HelloWorldAsyncResponseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. + * Copyright (c) 2021, 2024 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. @@ -32,7 +32,7 @@ import org.eclipse.microprofile.metrics.MetricID; import org.eclipse.microprofile.metrics.MetricRegistry; import org.eclipse.microprofile.metrics.Timer; -import org.eclipse.microprofile.metrics.annotation.RegistryType; +import org.eclipse.microprofile.metrics.annotation.RegistryScope; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -63,14 +63,12 @@ public class HelloWorldAsyncResponseTest { @Inject MetricRegistry registry; - // TODO change to RegistryScope once MP makes it a qualifier @Inject - @RegistryType(type = MetricRegistry.Type.BASE) + @RegistryScope(scope = MetricRegistry.BASE_SCOPE) private MetricRegistry syntheticTimerRegistry; - // TODO change to RegistryScope once MP makes it a qualifier @Inject - @RegistryType(type = MetricRegistry.Type.VENDOR) + @RegistryScope(scope = MetricRegistry.VENDOR_SCOPE) private MetricRegistry vendorRegistry; @Disabled diff --git a/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/HelloWorldResource.java b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/HelloWorldResource.java index dd5cbac3f51..c633f6a1d0c 100644 --- a/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/HelloWorldResource.java +++ b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/HelloWorldResource.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023 Oracle and/or its affiliates. + * Copyright (c) 2018, 2024 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. @@ -40,7 +40,7 @@ import org.eclipse.microprofile.metrics.Gauge; import org.eclipse.microprofile.metrics.MetricRegistry; import org.eclipse.microprofile.metrics.annotation.Counted; -import org.eclipse.microprofile.metrics.annotation.RegistryType; +import org.eclipse.microprofile.metrics.annotation.RegistryScope; import org.eclipse.microprofile.metrics.annotation.Timed; /** @@ -102,9 +102,8 @@ static long inflightRequestsCount(MetricRegistry metricRegistry) { @Inject MetricRegistry metricRegistry; - // TODO change to RegistryScope once MP makes it a qualifier @Inject - @RegistryType(type = MetricRegistry.Type.VENDOR) + @RegistryScope(scope = MetricRegistry.VENDOR_SCOPE) private MetricRegistry vendorRegistry; public HelloWorldResource() { diff --git a/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/HelloWorldRestEndpointSimpleTimerDisabledTest.java b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/HelloWorldRestEndpointSimpleTimerDisabledTest.java index 316960b14f6..3fedf98725d 100644 --- a/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/HelloWorldRestEndpointSimpleTimerDisabledTest.java +++ b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/HelloWorldRestEndpointSimpleTimerDisabledTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023 Oracle and/or its affiliates. + * Copyright (c) 2018, 2024 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. @@ -21,7 +21,7 @@ import jakarta.inject.Inject; import org.eclipse.microprofile.metrics.MetricRegistry; -import org.eclipse.microprofile.metrics.annotation.RegistryType; +import org.eclipse.microprofile.metrics.annotation.RegistryScope; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -41,9 +41,8 @@ static void init() { MetricsMpServiceTest.cleanUpSyntheticSimpleTimerRegistry(); } - // TODO change to RegistryScope once MP makes it a qualifier @Inject - @RegistryType(type = MetricRegistry.Type.BASE) + @RegistryScope(scope = MetricRegistry.BASE_SCOPE) MetricRegistry syntheticTimerRegistry; boolean isSyntheticSimpleTimerPresent() { diff --git a/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/MetricsMpServiceTest.java b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/MetricsMpServiceTest.java index 7a744e8729a..9ffb4758dcd 100644 --- a/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/MetricsMpServiceTest.java +++ b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/MetricsMpServiceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023 Oracle and/or its affiliates. + * Copyright (c) 2018, 2024 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. @@ -24,7 +24,7 @@ import org.eclipse.microprofile.metrics.Metadata; import org.eclipse.microprofile.metrics.MetricRegistry; import org.eclipse.microprofile.metrics.MetricUnits; -import org.eclipse.microprofile.metrics.annotation.RegistryType; +import org.eclipse.microprofile.metrics.annotation.RegistryScope; import org.junit.jupiter.api.AfterAll; /** @@ -48,9 +48,8 @@ static MetricRegistry cleanUpSyntheticSimpleTimerRegistry() { @Inject private MetricRegistry registry; - // TODO change to RegistryScope once MP makes it a qualifier @Inject - @RegistryType(type = MetricRegistry.Type.BASE) + @RegistryScope(scope = MetricRegistry.BASE_SCOPE) private MetricRegistry baseRegistry; MetricRegistry syntheticTimerTimerRegistry() { diff --git a/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestDistributionCustomizations.java b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestDistributionCustomizations.java new file mode 100644 index 00000000000..c015d0b1761 --- /dev/null +++ b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestDistributionCustomizations.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2024 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.microprofile.metrics; + +import io.helidon.microprofile.testing.junit5.AddConfig; +import io.helidon.microprofile.testing.junit5.HelidonTest; + +import jakarta.inject.Inject; +import org.eclipse.microprofile.metrics.Histogram; +import org.eclipse.microprofile.metrics.MetricID; +import org.eclipse.microprofile.metrics.MetricRegistry; +import org.eclipse.microprofile.metrics.Timer; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.arrayWithSize; +import static org.hamcrest.Matchers.greaterThan; + +@HelidonTest +@AddConfig(key = "mp.metrics.distribution.percentiles-histogram.enabled", + value = "alpha.*=true;alpha.nope=false") +class TestDistributionCustomizations { + + @Inject + private MetricRegistry metricRegistry; + + @Test + void checkDefaultedSummaryWithNoCustomization() { + Histogram histogram = metricRegistry.histogram("alpha.useDefaults"); + /* + Micrometer provides the buckets automatically. Just make sure there are some. + */ + assertThat("alpha.useDefaults", + histogram.getSnapshot().bucketValues(), + arrayWithSize(greaterThan(0))); + + Timer timer = metricRegistry.timer("alpha.timer"); + assertThat("alpha.timer", + timer.getSnapshot().bucketValues(), + arrayWithSize(greaterThan(0))); + } + + @Test + void checkNoDefaultDueToExclusion() { + Histogram histogram = metricRegistry.histogram("alpha.nope"); + assertThat("alpha.nope", + histogram.getSnapshot().bucketValues(), + arrayWithSize(0)); + + metricRegistry.remove(new MetricID("alpha.nope")); + + Timer timer = metricRegistry.timer("alpha.nope"); + assertThat("alpha.nope", + timer.getSnapshot().bucketValues(), + arrayWithSize(0)); + + timer = metricRegistry.timer("beta.anything"); + assertThat("beta.anything", + timer.getSnapshot().bucketValues(), + arrayWithSize(0)); + } +} diff --git a/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestGcTimeCounter.java b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestGcTimeCounter.java new file mode 100644 index 00000000000..d175ef97de0 --- /dev/null +++ b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestGcTimeCounter.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024 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.microprofile.metrics; + +import java.util.Map; + +import io.helidon.microprofile.testing.junit5.HelidonTest; + +import jakarta.inject.Inject; +import org.eclipse.microprofile.metrics.Counter; +import org.eclipse.microprofile.metrics.Metric; +import org.eclipse.microprofile.metrics.MetricID; +import org.eclipse.microprofile.metrics.MetricRegistry; +import org.eclipse.microprofile.metrics.annotation.RegistryScope; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.not; + +@HelidonTest +@Deprecated(since = "4.1", forRemoval = true) +@Disabled +class TestGcTimeCounter { + + @Inject + @RegistryScope(scope = MetricRegistry.BASE_SCOPE) + private MetricRegistry baseRegistry; + + @Test + void checkForCounter() { + + Map gcTimeMetrics = + baseRegistry.getMetrics((metricID, metric) -> metricID.getName().equals("gc.time")); + + assertThat("gc.time metric IDs", gcTimeMetrics.keySet(), not(empty())); + assertThat("gc.time metric", gcTimeMetrics.values().stream().findFirst().orElseThrow(), instanceOf(Counter.class)); + } + +} diff --git a/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestGcTimeGauge.java b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestGcTimeGauge.java new file mode 100644 index 00000000000..cb2129d36b7 --- /dev/null +++ b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/TestGcTimeGauge.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2024 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.microprofile.metrics; + +import java.util.Map; + +import io.helidon.microprofile.testing.junit5.AddConfig; +import io.helidon.microprofile.testing.junit5.HelidonTest; + +import jakarta.inject.Inject; +import org.eclipse.microprofile.metrics.Gauge; +import org.eclipse.microprofile.metrics.Metric; +import org.eclipse.microprofile.metrics.MetricID; +import org.eclipse.microprofile.metrics.MetricRegistry; +import org.eclipse.microprofile.metrics.annotation.RegistryScope; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.not; + +@HelidonTest +@AddConfig(key = "mp.metrics.gc-time-type", value = "gauge") +@Deprecated(since = "4.1", forRemoval = true) +class TestGcTimeGauge { + + @Inject + @RegistryScope(scope = MetricRegistry.BASE_SCOPE) + private MetricRegistry baseRegistry; + + @Test + void checkForGauge() { + + Map gcTimeMetrics = + baseRegistry.getMetrics((metricID, metric) -> metricID.getName().equals("gc.time")); + + assertThat("gc.time metric IDs", gcTimeMetrics.keySet(), not(empty())); + assertThat("gc.time metric", gcTimeMetrics.values().stream().findFirst().orElseThrow(), instanceOf(Gauge.class)); + } +} diff --git a/microprofile/tests/tck/tck-metrics/pom.xml b/microprofile/tests/tck/tck-metrics/pom.xml index 132edc07d8a..89423080d76 100644 --- a/microprofile/tests/tck/tck-metrics/pom.xml +++ b/microprofile/tests/tck/tck-metrics/pom.xml @@ -131,6 +131,10 @@ true + + gauge From 45f46c8f389908836b9d1e6d0cf692a6b124eef4 Mon Sep 17 00:00:00 2001 From: Jorge Bescos Gascon Date: Wed, 31 Jul 2024 14:14:01 +0200 Subject: [PATCH 09/37] 4.x: Helidon Webclient (4.0.10) is not routing the requests through proxy configured using Proxy Builder. #9022 (#9023) 4.x: Helidon Webclient (4.0.10) is not routing the requests through proxy configured using Proxy Builder. #9022 Signed-off-by: Jorge Bescos Gascon --- pom.xml | 6 ++ .../webclient/api/ClientRequestBase.java | 17 +++- .../java/io/helidon/webclient/api/Proxy.java | 74 +++++++++++----- .../http1/Http1ClientRequestImpl.java | 11 ++- webclient/tests/http1/pom.xml | 5 ++ .../webclient/tests/HttpMockProxyTest.java | 87 +++++++++++++++++++ .../webclient/tests/HttpProxyTest.java | 27 ++++-- .../webclient/tests/HttpsProxyTest.java | 15 +++- 8 files changed, 204 insertions(+), 38 deletions(-) create mode 100644 webclient/tests/http1/src/test/java/io/helidon/webclient/tests/HttpMockProxyTest.java diff --git a/pom.xml b/pom.xml index dcb99a6d96e..bd5f88935e0 100644 --- a/pom.xml +++ b/pom.xml @@ -79,6 +79,7 @@ 1.9.3 3.2.3 2.23.4 + 5.15.0 0.9.1 0.1.0 2.2.10 @@ -1035,6 +1036,11 @@ mockito-core ${version.lib.mockito} + + org.mock-server + mockserver-netty-no-dependencies + ${version.lib.mockserver} + org.eclipse.jgit org.eclipse.jgit.junit diff --git a/webclient/api/src/main/java/io/helidon/webclient/api/ClientRequestBase.java b/webclient/api/src/main/java/io/helidon/webclient/api/ClientRequestBase.java index e07cb562396..bdd3f053203 100644 --- a/webclient/api/src/main/java/io/helidon/webclient/api/ClientRequestBase.java +++ b/webclient/api/src/main/java/io/helidon/webclient/api/ClientRequestBase.java @@ -59,6 +59,10 @@ public abstract class ClientRequestBase, R extends Ht */ public static final Header USER_AGENT_HEADER = HeaderValues.create(HeaderNames.USER_AGENT, "Helidon " + Version.VERSION); + /** + * Proxy connection header. + */ + public static final Header PROXY_CONNECTION = HeaderValues.create("Proxy-Connection", "keep-alive"); private static final Map COUNTERS = new ConcurrentHashMap<>(); private static final Set SUPPORTED_SCHEMES = Set.of("https", "http"); @@ -253,7 +257,7 @@ public T proxy(Proxy proxy) { @Override public R request() { - headers.setIfAbsent(USER_AGENT_HEADER); + additionalHeaders(); return validateAndSubmit(BufferData.EMPTY_BYTES); } @@ -262,17 +266,24 @@ public final R submit(Object entity) { if (!(entity instanceof byte[] bytes && bytes.length == 0)) { rejectHeadWithEntity(); } - headers.setIfAbsent(USER_AGENT_HEADER); + additionalHeaders(); return validateAndSubmit(entity); } @Override public final R outputStream(OutputStreamHandler outputStreamConsumer) { rejectHeadWithEntity(); - headers.setIfAbsent(USER_AGENT_HEADER); + additionalHeaders(); return doOutputStream(outputStreamConsumer); } + /** + * Append additional headers before sending the request. + */ + protected void additionalHeaders() { + headers.setIfAbsent(USER_AGENT_HEADER); + } + /** * HTTP method to be invoked. * diff --git a/webclient/api/src/main/java/io/helidon/webclient/api/Proxy.java b/webclient/api/src/main/java/io/helidon/webclient/api/Proxy.java index 269d53136fc..22749b614e3 100644 --- a/webclient/api/src/main/java/io/helidon/webclient/api/Proxy.java +++ b/webclient/api/src/main/java/io/helidon/webclient/api/Proxy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2024 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. @@ -58,8 +58,6 @@ public class Proxy { private static final System.Logger LOGGER = System.getLogger(Proxy.class.getName()); private static final Tls NO_TLS = Tls.builder().enabled(false).build(); - private static final Header PROXY_CONNECTION = - HeaderValues.create("Proxy-Connection", "keep-alive"); /** * No proxy instance. @@ -90,6 +88,7 @@ public class Proxy { private final Optional password; private final ProxySelector systemProxySelector; private final Optional
proxyAuthHeader; + private final boolean forceHttpConnect; private Proxy(Proxy.Builder builder) { this.host = builder.host(); @@ -102,6 +101,7 @@ private Proxy(Proxy.Builder builder) { this.port = builder.port(); this.username = builder.username(); this.password = builder.password(); + this.forceHttpConnect = builder.forceHttpConnect(); if (type == ProxyType.SYSTEM) { this.noProxy = inetSocketAddress -> true; @@ -451,7 +451,8 @@ private static Optional isIpV6HostRegExp(String host) { private static Socket connectToProxy(WebClient webClient, InetSocketAddress proxyAddress, InetSocketAddress targetAddress, - Proxy proxy) { + Proxy proxy, + boolean tls) { WebClientConfig clientConfig = webClient.prototype(); TcpClientConnection connection = TcpClientConnection.create(webClient, @@ -469,26 +470,26 @@ private static Socket connectToProxy(WebClient webClient, it -> { }) .connect(); - - HttpClientRequest request = webClient.method(Method.CONNECT) - .followRedirects(false) // do not follow redirects for proxy connect itself - .connection(connection) - .uri("http://" + proxyAddress.getHostName() + ":" + proxyAddress.getPort()) - .protocolId("http/1.1") // MUST be 1.1, if not available, proxy connection will fail - .header(HeaderNames.HOST, targetAddress.getHostName() + ":" + targetAddress.getPort()) - .accept(MediaTypes.WILDCARD); - if (clientConfig.keepAlive()) { - request.header(HeaderValues.CONNECTION_KEEP_ALIVE) - .header(PROXY_CONNECTION); - } - proxy.proxyAuthHeader.ifPresent(request::header); - // we cannot close the response, as that would close the connection - HttpClientResponse response = request.request(); - if (response.status().family() != Status.Family.SUCCESSFUL) { - response.close(); - throw new IllegalStateException("Proxy sent wrong HTTP response code: " + response.status()); + if (proxy.forceHttpConnect || tls || proxy.username.isPresent()) { + HttpClientRequest request = webClient.method(Method.CONNECT) + .followRedirects(false) // do not follow redirects for proxy connect itself + .connection(connection) + .uri("http://" + proxyAddress.getHostName() + ":" + proxyAddress.getPort()) + .protocolId("http/1.1") // MUST be 1.1, if not available, proxy connection will fail + .header(HeaderNames.HOST, targetAddress.getHostName() + ":" + targetAddress.getPort()) + .accept(MediaTypes.WILDCARD); + if (clientConfig.keepAlive()) { + request.header(HeaderValues.CONNECTION_KEEP_ALIVE) + .header(ClientRequestBase.PROXY_CONNECTION); + } + proxy.proxyAuthHeader.ifPresent(request::header); + // we cannot close the response, as that would close the connection + HttpClientResponse response = request.request(); + if (response.status().family() != Status.Family.SUCCESSFUL) { + response.close(); + throw new IllegalStateException("Proxy sent wrong HTTP response code: " + response.status()); + } } - return connection.socket(); } @@ -562,7 +563,8 @@ Socket connect(WebClient webClient, .map(proxyAddress -> connectToProxy(webClient, proxyAddress, targetAddress, - proxy)) + proxy, + tls)) .orElseGet(() -> NONE.connect(webClient, proxy, targetAddress, socketOptions, tls)); } }; @@ -587,6 +589,7 @@ public static class Builder implements io.helidon.common.Builder private int port = 80; private String username; private char[] password; + private boolean forceHttpConnect = false; private Builder() { } @@ -632,6 +635,11 @@ public Proxy build() { * Proxy password * * + * httpConnect + * {@code false} + * Specify whether the HTTP client will always execute HTTP CONNECT. + * + * * no-proxy * {@code no default} * Contains list of the hosts which should be excluded from using proxy @@ -667,6 +675,20 @@ public Builder type(ProxyType type) { return this; } + /** + * Forces HTTP CONNECT with the proxy server. + * Otherwise it will not execute HTTP CONNECT when the request is + * plain HTTP with no authentication. + * + * @param forceHttpConnect HTTP CONNECT + * @return updated builder instance + */ + @ConfiguredOption + public Builder forceHttpConnect(boolean forceHttpConnect) { + this.forceHttpConnect = forceHttpConnect; + return this; + } + /** * Sets a new host value. * @@ -742,6 +764,10 @@ ProxyType type() { return type; } + boolean forceHttpConnect() { + return forceHttpConnect; + } + String host() { return host; } diff --git a/webclient/http1/src/main/java/io/helidon/webclient/http1/Http1ClientRequestImpl.java b/webclient/http1/src/main/java/io/helidon/webclient/http1/Http1ClientRequestImpl.java index 85da8835b6e..22260adcaed 100644 --- a/webclient/http1/src/main/java/io/helidon/webclient/http1/Http1ClientRequestImpl.java +++ b/webclient/http1/src/main/java/io/helidon/webclient/http1/Http1ClientRequestImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. + * Copyright (c) 2022, 2024 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. @@ -31,6 +31,7 @@ import io.helidon.http.media.MediaContext; import io.helidon.webclient.api.ClientRequestBase; import io.helidon.webclient.api.ClientUri; +import io.helidon.webclient.api.Proxy.ProxyType; import io.helidon.webclient.api.WebClientServiceRequest; import io.helidon.webclient.api.WebClientServiceResponse; @@ -179,6 +180,14 @@ protected MediaContext mediaContext() { return super.mediaContext(); } + @Override + protected void additionalHeaders() { + super.additionalHeaders(); + if (proxy().type() != ProxyType.NONE) { + header(PROXY_CONNECTION); + } + } + Http1ClientImpl http1Client() { return http1Client; } diff --git a/webclient/tests/http1/pom.xml b/webclient/tests/http1/pom.xml index 318419589d8..cd2d23777f0 100644 --- a/webclient/tests/http1/pom.xml +++ b/webclient/tests/http1/pom.xml @@ -67,5 +67,10 @@ vertx-core test + + org.mock-server + mockserver-netty-no-dependencies + test + diff --git a/webclient/tests/http1/src/test/java/io/helidon/webclient/tests/HttpMockProxyTest.java b/webclient/tests/http1/src/test/java/io/helidon/webclient/tests/HttpMockProxyTest.java new file mode 100644 index 00000000000..7b1b4fa841b --- /dev/null +++ b/webclient/tests/http1/src/test/java/io/helidon/webclient/tests/HttpMockProxyTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2024 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.webclient.tests; + +import static io.helidon.http.Method.GET; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.mockserver.integration.ClientAndServer.startClientAndServer; +import static org.mockserver.model.HttpForward.forward; +import static org.mockserver.model.HttpRequest.request; + +import io.helidon.http.Status; +import io.helidon.webclient.api.HttpClientResponse; +import io.helidon.webclient.api.Proxy; +import io.helidon.webclient.api.WebClient; +import io.helidon.webserver.WebServer; +import io.helidon.webserver.http.HttpRouting; +import io.helidon.webserver.testing.junit5.ServerTest; +import io.helidon.webserver.testing.junit5.SetUpRoute; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockserver.integration.ClientAndServer; +import org.mockserver.model.HttpForward.Scheme; + +@ServerTest +class HttpMockProxyTest { + + private static final int PROXY_PORT = 1080; + private final WebClient webClient; + private final int serverPort; + private ClientAndServer mockServer; + + HttpMockProxyTest(WebServer server) { + this.serverPort = server.port(); + this.webClient = WebClient.builder() + .baseUri("http://localhost:" + serverPort) + .proxy(Proxy.builder().host("localhost").port(PROXY_PORT).build()) + .build(); + } + + @SetUpRoute + static void routing(HttpRouting.Builder router) { + router.route(GET, "/get", Routes::get); + } + + @BeforeEach + public void before() { + mockServer = startClientAndServer(PROXY_PORT); + mockServer.when(request()).forward(forward().withScheme(Scheme.HTTP).withHost("localhost").withPort(serverPort)); + } + + @AfterEach + public void after() { + mockServer.stop(); + } + + @Test + public void issue9022() { + try (HttpClientResponse response = webClient.get("/get").request()) { + assertThat(response.status(), is(Status.OK_200)); + String entity = response.entity().as(String.class); + assertThat(entity, is("Hello")); + } + } + + private static class Routes { + private static String get() { + return "Hello"; + } + } +} diff --git a/webclient/tests/http1/src/test/java/io/helidon/webclient/tests/HttpProxyTest.java b/webclient/tests/http1/src/test/java/io/helidon/webclient/tests/HttpProxyTest.java index 17dec4e243d..973e9f813c3 100644 --- a/webclient/tests/http1/src/test/java/io/helidon/webclient/tests/HttpProxyTest.java +++ b/webclient/tests/http1/src/test/java/io/helidon/webclient/tests/HttpProxyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2024 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. @@ -20,6 +20,8 @@ import java.net.ProxySelector; import io.helidon.http.Status; +import io.helidon.webclient.api.ClientRequest; +import io.helidon.webclient.api.ClientRequestBase; import io.helidon.webclient.api.HttpClient; import io.helidon.webclient.api.HttpClientResponse; import io.helidon.webclient.api.Proxy; @@ -39,6 +41,8 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; @ServerTest class HttpProxyTest { @@ -128,37 +132,37 @@ void testNoHosts2() { @Test void testNoProxyTypeButHasHost1() { - Proxy proxy = Proxy.builder().host(PROXY_HOST).port(proxyPort).build(); + Proxy proxy = Proxy.builder().forceHttpConnect(true).host(PROXY_HOST).port(proxyPort).build(); successVerify(proxy, clientHttp1); } @Test void testNoProxyTypeButHasHost2() { - Proxy proxy = Proxy.builder().host(PROXY_HOST).port(proxyPort).build(); + Proxy proxy = Proxy.builder().forceHttpConnect(true).host(PROXY_HOST).port(proxyPort).build(); successVerify(proxy, clientHttp2); } @Test void testProxyNoneTypeButHasHost1() { - Proxy proxy = Proxy.builder().type(ProxyType.NONE).host(PROXY_HOST).port(proxyPort).build(); + Proxy proxy = Proxy.builder().forceHttpConnect(true).type(ProxyType.NONE).host(PROXY_HOST).port(proxyPort).build(); successVerify(proxy, clientHttp1); } @Test void testProxyNoneTypeButHasHost2() { - Proxy proxy = Proxy.builder().type(ProxyType.NONE).host(PROXY_HOST).port(proxyPort).build(); + Proxy proxy = Proxy.builder().forceHttpConnect(true).type(ProxyType.NONE).host(PROXY_HOST).port(proxyPort).build(); successVerify(proxy, clientHttp2); } @Test void testSimpleProxy1() { - Proxy proxy = Proxy.builder().type(ProxyType.HTTP).host(PROXY_HOST).port(proxyPort).build(); + Proxy proxy = Proxy.builder().forceHttpConnect(true).type(ProxyType.HTTP).host(PROXY_HOST).port(proxyPort).build(); successVerify(proxy, clientHttp1); } @Test void testSimpleProxy2() { - Proxy proxy = Proxy.builder().type(ProxyType.HTTP).host(PROXY_HOST).port(proxyPort).build(); + Proxy proxy = Proxy.builder().forceHttpConnect(true).type(ProxyType.HTTP).host(PROXY_HOST).port(proxyPort).build(); successVerify(proxy, clientHttp2); } @@ -197,11 +201,18 @@ private void noHosts(HttpClient client) { } private void successVerify(Proxy proxy, HttpClient client) { - try (HttpClientResponse response = client.get("/get").proxy(proxy).request()) { + ClientRequest request = client.get("/get").proxy(proxy); + try (HttpClientResponse response = request.request()) { assertThat(response.status(), is(Status.OK_200)); String entity = response.entity().as(String.class); assertThat(entity, is("Hello")); } + boolean proxyConnection = request.headers().contains(ClientRequestBase.PROXY_CONNECTION); + if (client == clientHttp1) { + assertTrue(proxyConnection, "HTTP1 requires Proxy-Connection header"); + } else { + assertFalse(proxyConnection, "HTTP2 does not allow Proxy-Connection header"); + } assertThat(httpProxy.counter(), is(1)); } diff --git a/webclient/tests/http1/src/test/java/io/helidon/webclient/tests/HttpsProxyTest.java b/webclient/tests/http1/src/test/java/io/helidon/webclient/tests/HttpsProxyTest.java index ad29a424f49..11e8e10c172 100644 --- a/webclient/tests/http1/src/test/java/io/helidon/webclient/tests/HttpsProxyTest.java +++ b/webclient/tests/http1/src/test/java/io/helidon/webclient/tests/HttpsProxyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2024 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. @@ -24,6 +24,8 @@ import io.helidon.common.pki.Keys; import io.helidon.common.tls.Tls; import io.helidon.http.Status; +import io.helidon.webclient.api.ClientRequest; +import io.helidon.webclient.api.ClientRequestBase; import io.helidon.webclient.api.HttpClient; import io.helidon.webclient.api.HttpClientResponse; import io.helidon.webclient.api.Proxy; @@ -44,6 +46,8 @@ import static io.helidon.http.Method.GET; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; @ServerTest class HttpsProxyTest { @@ -182,11 +186,18 @@ void testSystemProxy2() { } private void successVerify(Proxy proxy, HttpClient client) { - try (HttpClientResponse response = client.get("/get").proxy(proxy).request()) { + ClientRequest request = client.get("/get").proxy(proxy); + try (HttpClientResponse response = request.request()) { assertThat(response.status(), is(Status.OK_200)); String entity = response.entity().as(String.class); assertThat(entity, is("Hello")); } + boolean proxyConnection = request.headers().contains(ClientRequestBase.PROXY_CONNECTION); + if (client == clientHttp1) { + assertTrue(proxyConnection, "HTTP1 requires Proxy-Connection header"); + } else { + assertFalse(proxyConnection, "HTTP2 does not allow Proxy-Connection header"); + } } private void noProxyChecks(HttpClient client) { From 01595a3984ed5be5816fba472ad5a12cb6895f3e Mon Sep 17 00:00:00 2001 From: Joe DiPol Date: Wed, 31 Jul 2024 12:24:27 -0700 Subject: [PATCH 10/37] Upgrade snakeyaml to 2.2 (#9072) --- dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/pom.xml b/dependencies/pom.xml index 2e07bc33492..a7d74f72a8e 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -152,7 +152,7 @@ 1.0.4 2.0.9 3.3.4 - 2.0 + 2.2 1.19.3 1.4.2 2.1.5 From 1cad37728cb751a8302b8d3f38480485ba24d3f7 Mon Sep 17 00:00:00 2001 From: Tomas Langer Date: Thu, 1 Aug 2024 00:06:31 +0200 Subject: [PATCH 11/37] 4.x: Config reference documentation (#9053) * Update of config-metadata module: - introduction of codegen module (replaces processor) - introduction of docs module (to generate documentation from metadata JSON) - deprecated processor - updated docs and moved it from docs-internal Updates to bom pom, and all pom * Fixes to all pom files to use the new config metadata codegen - fixed plugin dependencies - fixed that dependency for config metadata is always optional - removed dependencies on annotation processors from dependency sections * Docs update: - introducing profile to update config reference documentation - introducing updated readme (moved from internal docs) - a few docs fixes in classes discovered when testing * Enable generating into an empty directory (once we remove the files from git). Using template for config_reference. * Regenerated configuration metadata, and a reference fix. --- all/pom.xml | 10 + bom/pom.xml | 10 + common/configurable/pom.xml | 16 +- .../AllowListConfigBlueprint.java | 4 +- common/key-util/pom.xml | 8 +- common/socket/pom.xml | 8 +- common/tls/pom.xml | 16 +- .../common/tls/TlsConfigBlueprint.java | 2 +- config/config-mp/pom.xml | 28 +- .../config/metadata/processor/JArray.java | 42 - .../config/metadata/processor/JObject.java | 113 --- .../metadata/README.md | 126 ++- config/metadata/codegen/pom.xml | 63 ++ .../ConfigMetadataCodegenExtension.java | 114 +++ .../ConfigMetadataCodegenProvider.java | 53 ++ .../metadata/codegen/ConfigMetadataTypes.java | 55 ++ .../codegen/ConfiguredAnnotation.java | 75 ++ .../codegen/ConfiguredOptionData.java | 298 +++++++ .../metadata/codegen/ConfiguredType.java | 341 +++++++ .../config/metadata/codegen/Javadoc.java | 110 +++ .../config/metadata/codegen/OptionType.java | 22 + .../config/metadata/codegen/TypeHandler.java | 24 + .../metadata/codegen/TypeHandlerBase.java | 182 ++++ .../codegen/TypeHandlerBuilderApi.java | 237 +++++ .../metadata/codegen/TypeHandlerMetaApi.java | 380 ++++++++ .../metadata/codegen/TypeHandlerResult.java | 31 + .../config/metadata/codegen/package-info.java | 25 + .../codegen/src/main/java/module-info.java | 30 + config/metadata/docs/etc/spotbugs/exclude.xml | 32 + config/metadata/docs/pom.xml | 145 +++ .../config/metadata/docs/CmAllowedValue.java | 67 ++ .../config/metadata/docs/CmModule.java | 69 ++ .../config/metadata/docs/CmOption.java | 323 +++++++ .../config/metadata/docs/CmReference.java | 48 + .../helidon/config/metadata/docs/CmType.java | 254 ++++++ .../config/metadata/docs/ConfigDocs.java | 844 ++++++++++++++++++ .../metadata/docs/ConfigDocsException.java | 43 + .../io/helidon/config/metadata/docs/Main.java | 74 ++ .../config/metadata/docs}/package-info.java | 6 +- .../metadata/docs/config_reference.adoc.hbs | 42 + .../config/metadata/docs/type-docs.adoc.hbs | 86 ++ .../src/main/resources/logging.properties | 21 + .../docs/ConfigDocumentationTest.java | 90 ++ config/metadata/metadata/pom.xml | 53 ++ .../helidon/config/metadata/Configured.java | 2 +- .../config/metadata/ConfiguredOption.java | 2 +- .../config/metadata/ConfiguredOptions.java | 2 +- .../config/metadata/ConfiguredValue.java | 2 +- .../helidon/config/metadata/package-info.java | 2 +- .../src/main/java/module-info.java | 2 +- config/metadata/pom.xml | 48 +- .../processor}/pom.xml | 7 +- .../metadata/processor/BlueprintUtil.java | 2 +- .../processor/ConfigMetadataHandler.java | 16 +- .../processor/ConfigMetadataProcessor.java | 9 +- .../processor/ConfiguredAnnotation.java | 2 +- .../processor/ConfiguredOptionData.java | 2 +- .../metadata/processor/ConfiguredType.java | 71 +- .../config/metadata/processor/Javadoc.java | 7 +- .../metadata/processor/TypeHandler.java | 2 +- .../metadata/processor/TypeHandlerBase.java | 0 .../processor/TypeHandlerBuilderApi.java | 0 .../processor/TypeHandlerMetaApi.java | 2 +- .../processor/TypeHandlerMetaApiBase.java | 2 +- .../TypeHandlerMetaApiBlueprint.java | 2 +- .../metadata/processor/TypeHandlerResult.java | 2 +- .../config/metadata/processor/UsedTypes.java | 3 +- .../metadata/processor/package-info.java | 23 + .../processor}/src/main/java/module-info.java | 6 +- .../processor/ConfigMetadataHandlerTest.java | 2 +- config/pom.xml | 1 - .../tests/config-metadata-builder-api/pom.xml | 8 +- config/tests/config-metadata-meta-api/pom.xml | 18 +- cors/pom.xml | 18 +- dbclient/hikari/pom.xml | 8 +- .../hikari/src/main/java/module-info.java | 5 +- dbclient/jdbc/pom.xml | 9 +- dbclient/jdbc/src/main/java/module-info.java | 3 +- docs/README.md | 5 + docs/pom.xml | 33 + .../asciidoc/config/config_reference.adoc | 9 +- ...helidon_common_configurable_AllowList.adoc | 22 +- ..._helidon_common_configurable_LruCache.adoc | 2 +- ..._helidon_common_configurable_Resource.adoc | 24 +- ...onfigurable_ScheduledThreadPoolConfig.adoc | 20 +- ...figurable_ScheduledThreadPoolSupplier.adoc | 20 +- ..._common_configurable_ThreadPoolConfig.adoc | 46 +- ...ommon_configurable_ThreadPoolSupplier.adoc | 46 +- .../config/io_helidon_common_pki_Keys.adoc | 12 +- .../io_helidon_common_pki_KeystoreKeys.adoc | 28 +- .../config/io_helidon_common_pki_PemKeys.adoc | 12 +- ...o_helidon_common_socket_SocketOptions.adoc | 30 +- ...o_helidon_common_tls_RevocationConfig.adoc | 38 +- .../config/io_helidon_common_tls_Tls.adoc | 75 +- ...on_dbclient_jdbc_JdbcParametersConfig.adoc | 46 +- .../io_helidon_faulttolerance_Async.adoc | 4 +- .../io_helidon_faulttolerance_Bulkhead.adoc | 10 +- ...helidon_faulttolerance_CircuitBreaker.adoc | 22 +- .../io_helidon_faulttolerance_Retry.adoc | 20 +- .../io_helidon_faulttolerance_Timeout.adoc | 8 +- ...don_http_RequestedUriDiscoveryContext.adoc | 13 + ..._http_encoding_ContentEncodingContext.adoc | 4 +- .../io_helidon_http_media_MediaContext.adoc | 12 +- .../io_helidon_integrations_neo4j_Neo4j.adoc | 7 + ...tegrations_oci_ConfigFileMethodConfig.adoc | 4 +- ...n_integrations_oci_ConfigMethodConfig.adoc | 35 +- ...don_integrations_oci_ImdsInstanceInfo.adoc | 75 ++ ...io_helidon_integrations_oci_OciConfig.adoc | 68 +- ...grations_oci_SessionTokenMethodConfig.adoc | 61 +- ...rations_oci_metrics_OciMetricsSupport.adoc | 20 +- ...ntegrations_oci_sdk_runtime_OciConfig.adoc | 181 ++-- ...ertificates_OciCertificatesTlsManager.adoc | 24 +- ...don_integrations_openapi_ui_OpenApiUi.adoc | 6 +- ..._KeyPerformanceIndicatorMetricsConfig.adoc | 4 +- .../io_helidon_metrics_api_MetricsConfig.adoc | 38 +- .../io_helidon_metrics_api_ScopeConfig.adoc | 8 +- .../io_helidon_metrics_api_ScopingConfig.adoc | 8 +- .../config/io_helidon_microprofile_jwt.adoc | 90 -- ...microprofile_jwt_auth_JwtAuthProvider.adoc | 90 ++ ...rofile_openapi_MpOpenApiManagerConfig.adoc | 4 +- .../io_helidon_openapi_OpenApiFeature.adoc | 24 +- .../config/io_helidon_scheduling_Cron.adoc | 6 +- .../io_helidon_scheduling_FixedRate.adoc | 34 +- .../config/io_helidon_security_Security.adoc | 26 +- .../io_helidon_security_SecurityTime.adoc | 4 +- ...urity_providers_common_EvictableCache.adoc | 6 +- ...urity_providers_common_OutboundTarget.adoc | 22 +- ...ders_config_vault_ConfigVaultProvider.adoc | 64 ++ ...ult_ConfigVaultProvider_SecretConfig.adoc} | 21 +- ...ders_google_login_GoogleTokenProvider.adoc | 4 +- ...ty_providers_header_HeaderAtnProvider.adoc | 6 +- ...viders_httpauth_HttpBasicAuthProvider.adoc | 6 +- ...iders_httpauth_HttpDigestAuthProvider.adoc | 28 +- ...y_providers_httpsign_HttpSignProvider.adoc | 130 +-- ...ders_httpsign_InboundClientDefinition.adoc | 4 +- ..._idcs_mapper_IdcsMtRoleMapperProvider.adoc | 18 +- ...rs_idcs_mapper_IdcsRoleMapperProvider.adoc | 14 +- ...er_IdcsRoleMapperProviderBase_Builder.adoc | 14 +- ...on_security_providers_jwt_JwtProvider.adoc | 30 +- ..._security_providers_oidc_OidcProvider.adoc | 189 ++-- ...ity_providers_oidc_common_BaseBuilder.adoc | 77 +- ...rity_providers_oidc_common_OidcConfig.adoc | 183 ++-- ...ty_providers_oidc_common_TenantConfig.adoc | 77 +- .../config/io_helidon_tracing_Tracer.adoc | 25 +- ..._providers_jaeger_JaegerTracerBuilder.adoc | 25 +- ..._providers_zipkin_ZipkinTracerBuilder.adoc | 8 +- ...elidon_webclient_api_HttpClientConfig.adoc | 90 +- ..._helidon_webclient_api_HttpConfigBase.adoc | 32 +- .../io_helidon_webclient_api_Proxy.adoc | 11 +- .../io_helidon_webclient_api_WebClient.adoc | 92 +- ..._webclient_api_WebClientCookieManager.adoc | 6 +- .../io_helidon_webclient_grpc_GrpcClient.adoc | 2 +- ...bclient_grpc_GrpcClientProtocolConfig.adoc | 26 +- ...lient_http1_Http1ClientProtocolConfig.adoc | 20 +- ...lient_http2_Http2ClientProtocolConfig.adoc | 58 +- ..._helidon_webclient_websocket_WsClient.adoc | 2 +- ...io_helidon_webserver_ConnectionConfig.adoc | 44 +- .../io_helidon_webserver_ListenerConfig.adoc | 124 +-- .../io_helidon_webserver_WebServer.adoc | 136 +-- ...n_webserver_accesslog_AccessLogConfig.adoc | 122 +-- ..._webserver_accesslog_AccessLogFeature.adoc | 122 +-- ...idon_webserver_context_ContextFeature.adoc | 6 +- .../io_helidon_webserver_cors_CorsConfig.adoc | 8 +- ...io_helidon_webserver_cors_CorsFeature.adoc | 8 +- ...don_webserver_grpc_GrpcTracingConfig.adoc} | 20 +- ...o_helidon_webserver_http1_Http1Config.adoc | 50 +- ...o_helidon_webserver_http2_Http2Config.adoc | 86 +- ...idon_webserver_observe_ObserveFeature.adoc | 28 +- ..._webserver_observe_ObserverConfigBase.adoc | 2 +- ...bserver_observe_config_ConfigObserver.adoc | 6 +- ...bserver_observe_health_HealthObserver.adoc | 20 +- ...n_webserver_observe_info_InfoObserver.adoc | 2 +- ...don_webserver_observe_log_LogObserver.adoc | 4 +- ...webserver_observe_log_LogStreamConfig.adoc | 14 +- ...erver_observe_metrics_MetricsObserver.adoc | 36 +- ...erver_observe_tracing_TracingObserver.adoc | 10 +- ...elidon_webserver_security_PathsConfig.adoc | 36 +- ...on_webserver_security_SecurityFeature.adoc | 18 +- ...on_webserver_security_SecurityHandler.adoc | 36 +- ..._helidon_webserver_websocket_WsConfig.adoc | 8 +- .../config/io_opentracing_Tracer.adoc | 8 +- docs/src/main/asciidoc/mp/jwt.adoc | 2 +- fault-tolerance/fault-tolerance/pom.xml | 8 +- http/encoding/encoding/pom.xml | 8 +- http/http/pom.xml | 18 +- http/media/media/pom.xml | 8 +- integrations/micrometer/micrometer/pom.xml | 31 +- integrations/neo4j/neo4j/pom.xml | 26 +- integrations/oci/metrics/metrics/pom.xml | 18 +- integrations/oci/oci/pom.xml | 8 +- integrations/oci/tls-certificates/pom.xml | 8 +- integrations/openapi-ui/pom.xml | 8 +- integrations/vault/auths/approle/pom.xml | 4 +- lra/coordinator/server/pom.xml | 1 + metrics/api/pom.xml | 8 +- microprofile/jwt-auth/pom.xml | 32 + .../jwt/auth/JwtAuthProvider.java | 52 +- .../jwt-auth/src/main/java/module-info.java | 3 +- microprofile/lra/jax-rs/pom.xml | 17 + microprofile/openapi/pom.xml | 13 +- microprofile/server/pom.xml | 31 +- openapi/openapi/pom.xml | 8 +- scheduling/pom.xml | 41 +- security/providers/abac/pom.xml | 23 +- security/providers/common/pom.xml | 18 +- security/providers/config-vault/pom.xml | 32 +- security/providers/google-login/pom.xml | 31 +- security/providers/header/pom.xml | 31 +- security/providers/http-auth/pom.xml | 31 +- security/providers/http-sign/pom.xml | 31 +- security/providers/idcs-mapper/pom.xml | 31 +- security/providers/jwt/pom.xml | 33 +- security/providers/oidc-common/pom.xml | 18 +- security/providers/oidc/pom.xml | 23 +- security/security/pom.xml | 26 +- security/util/pom.xml | 18 +- tracing/providers/jaeger/pom.xml | 31 +- tracing/providers/opentracing/pom.xml | 21 +- tracing/providers/zipkin/pom.xml | 26 +- tracing/tracing/pom.xml | 26 +- webclient/api/pom.xml | 8 +- webclient/grpc/pom.xml | 30 +- webclient/http1/pom.xml | 8 +- webclient/http2/pom.xml | 8 +- webclient/websocket/pom.xml | 8 +- webserver/access-log/pom.xml | 8 +- webserver/context/pom.xml | 8 +- webserver/cors/pom.xml | 8 +- webserver/grpc/pom.xml | 8 +- webserver/http2/pom.xml | 8 +- webserver/observe/config/pom.xml | 8 +- webserver/observe/health/pom.xml | 8 +- webserver/observe/info/pom.xml | 8 +- webserver/observe/log/pom.xml | 8 +- webserver/observe/metrics/pom.xml | 8 +- webserver/observe/observe/pom.xml | 8 +- webserver/observe/tracing/pom.xml | 8 +- webserver/security/pom.xml | 8 +- webserver/service-common/pom.xml | 21 +- .../servicecommon/RestServiceSettings.java | 3 +- webserver/sse/pom.xml | 8 +- webserver/webserver/pom.xml | 8 +- webserver/websocket/pom.xml | 8 +- 243 files changed, 7398 insertions(+), 2151 deletions(-) delete mode 100644 config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/JArray.java delete mode 100644 config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/JObject.java rename docs-internal/config-metadata.md => config/metadata/README.md (58%) create mode 100644 config/metadata/codegen/pom.xml create mode 100644 config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/ConfigMetadataCodegenExtension.java create mode 100644 config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/ConfigMetadataCodegenProvider.java create mode 100644 config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/ConfigMetadataTypes.java create mode 100644 config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/ConfiguredAnnotation.java create mode 100644 config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/ConfiguredOptionData.java create mode 100644 config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/ConfiguredType.java create mode 100644 config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/Javadoc.java create mode 100644 config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/OptionType.java create mode 100644 config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/TypeHandler.java create mode 100644 config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/TypeHandlerBase.java create mode 100644 config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/TypeHandlerBuilderApi.java create mode 100644 config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/TypeHandlerMetaApi.java create mode 100644 config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/TypeHandlerResult.java create mode 100644 config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/package-info.java create mode 100644 config/metadata/codegen/src/main/java/module-info.java create mode 100644 config/metadata/docs/etc/spotbugs/exclude.xml create mode 100644 config/metadata/docs/pom.xml create mode 100644 config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/CmAllowedValue.java create mode 100644 config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/CmModule.java create mode 100644 config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/CmOption.java create mode 100644 config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/CmReference.java create mode 100644 config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/CmType.java create mode 100644 config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/ConfigDocs.java create mode 100644 config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/ConfigDocsException.java create mode 100644 config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/Main.java rename config/{metadata-processor/src/main/java/io/helidon/config/metadata/processor => metadata/docs/src/main/java/io/helidon/config/metadata/docs}/package-info.java (75%) create mode 100644 config/metadata/docs/src/main/resources/io/helidon/config/metadata/docs/config_reference.adoc.hbs create mode 100644 config/metadata/docs/src/main/resources/io/helidon/config/metadata/docs/type-docs.adoc.hbs create mode 100644 config/metadata/docs/src/main/resources/logging.properties create mode 100644 config/metadata/docs/src/test/java/io/helidon/config/metadata/docs/ConfigDocumentationTest.java create mode 100644 config/metadata/metadata/pom.xml rename config/metadata/{ => metadata}/src/main/java/io/helidon/config/metadata/Configured.java (98%) rename config/metadata/{ => metadata}/src/main/java/io/helidon/config/metadata/ConfiguredOption.java (99%) rename config/metadata/{ => metadata}/src/main/java/io/helidon/config/metadata/ConfiguredOptions.java (95%) rename config/metadata/{ => metadata}/src/main/java/io/helidon/config/metadata/ConfiguredValue.java (94%) rename config/metadata/{ => metadata}/src/main/java/io/helidon/config/metadata/package-info.java (92%) rename config/metadata/{ => metadata}/src/main/java/module-info.java (92%) rename config/{metadata-processor => metadata/processor}/pom.xml (89%) rename config/{metadata-processor => metadata/processor}/src/main/java/io/helidon/config/metadata/processor/BlueprintUtil.java (99%) rename config/{metadata-processor => metadata/processor}/src/main/java/io/helidon/config/metadata/processor/ConfigMetadataHandler.java (94%) rename config/{metadata-processor => metadata/processor}/src/main/java/io/helidon/config/metadata/processor/ConfigMetadataProcessor.java (84%) rename config/{metadata-processor => metadata/processor}/src/main/java/io/helidon/config/metadata/processor/ConfiguredAnnotation.java (98%) rename config/{metadata-processor => metadata/processor}/src/main/java/io/helidon/config/metadata/processor/ConfiguredOptionData.java (99%) rename config/{metadata-processor => metadata/processor}/src/main/java/io/helidon/config/metadata/processor/ConfiguredType.java (80%) rename config/{metadata-processor => metadata/processor}/src/main/java/io/helidon/config/metadata/processor/Javadoc.java (95%) rename config/{metadata-processor => metadata/processor}/src/main/java/io/helidon/config/metadata/processor/TypeHandler.java (92%) rename config/{metadata-processor => metadata/processor}/src/main/java/io/helidon/config/metadata/processor/TypeHandlerBase.java (100%) rename config/{metadata-processor => metadata/processor}/src/main/java/io/helidon/config/metadata/processor/TypeHandlerBuilderApi.java (100%) rename config/{metadata-processor => metadata/processor}/src/main/java/io/helidon/config/metadata/processor/TypeHandlerMetaApi.java (99%) rename config/{metadata-processor => metadata/processor}/src/main/java/io/helidon/config/metadata/processor/TypeHandlerMetaApiBase.java (98%) rename config/{metadata-processor => metadata/processor}/src/main/java/io/helidon/config/metadata/processor/TypeHandlerMetaApiBlueprint.java (98%) rename config/{metadata-processor => metadata/processor}/src/main/java/io/helidon/config/metadata/processor/TypeHandlerResult.java (94%) rename config/{metadata-processor => metadata/processor}/src/main/java/io/helidon/config/metadata/processor/UsedTypes.java (95%) create mode 100644 config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/package-info.java rename config/{metadata-processor => metadata/processor}/src/main/java/module-info.java (79%) rename config/{metadata-processor => metadata/processor}/src/test/java/io/helidon/config/metadata/processor/ConfigMetadataHandlerTest.java (95%) create mode 100644 docs/src/main/asciidoc/config/io_helidon_integrations_oci_ImdsInstanceInfo.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_microprofile_jwt.adoc create mode 100644 docs/src/main/asciidoc/config/io_helidon_microprofile_jwt_auth_JwtAuthProvider.adoc create mode 100644 docs/src/main/asciidoc/config/io_helidon_security_providers_config_vault_ConfigVaultProvider.adoc rename docs/src/main/asciidoc/config/{io_helidon_webserver_servicecommon_RestServiceSettings_Builder.adoc => io_helidon_security_providers_config_vault_ConfigVaultProvider_SecretConfig.adoc} (52%) rename docs/src/main/asciidoc/config/{io_helidon_metrics_api_ComponentMetricsSettings_Builder.adoc => io_helidon_webserver_grpc_GrpcTracingConfig.adoc} (63%) diff --git a/all/pom.xml b/all/pom.xml index 0e02a55378b..7bf40904ed8 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -133,6 +133,16 @@ io.helidon.config helidon-config-metadata-processor + + io.helidon.config.metadata + helidon-config-metadata-codegen + + io.helidon.security helidon-security diff --git a/bom/pom.xml b/bom/pom.xml index 92948eff2a0..adddfc941d6 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -202,6 +202,16 @@ helidon-config-metadata-processor ${helidon.version} + + io.helidon.config.metadata + helidon-config-metadata-codegen + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-docs + ${helidon.version} + io.helidon.security diff --git a/common/configurable/pom.xml b/common/configurable/pom.xml index fb860e83e30..e98daecbe52 100644 --- a/common/configurable/pom.xml +++ b/common/configurable/pom.xml @@ -95,13 +95,13 @@ true - io.helidon.config - helidon-config-metadata-processor + io.helidon.codegen + helidon-codegen-apt ${helidon.version} - io.helidon.codegen - helidon-codegen-apt + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} @@ -130,13 +130,13 @@ - io.helidon.config - helidon-config-metadata-processor + io.helidon.codegen + helidon-codegen-apt ${helidon.version} - io.helidon.codegen - helidon-codegen-apt + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} diff --git a/common/configurable/src/main/java/io/helidon/common/configurable/AllowListConfigBlueprint.java b/common/configurable/src/main/java/io/helidon/common/configurable/AllowListConfigBlueprint.java index 1a3f6ab2bfe..a42923ec308 100644 --- a/common/configurable/src/main/java/io/helidon/common/configurable/AllowListConfigBlueprint.java +++ b/common/configurable/src/main/java/io/helidon/common/configurable/AllowListConfigBlueprint.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2024 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. @@ -87,7 +87,7 @@ interface AllowListConfigBlueprint extends Prototype.Factory { /** * Exact strings to deny. * - * @return exact strings to allow + * @return exact strings to deny */ @Option.Configured("deny.exact") @Option.Singular diff --git a/common/key-util/pom.xml b/common/key-util/pom.xml index b2a994bea50..473ac884652 100644 --- a/common/key-util/pom.xml +++ b/common/key-util/pom.xml @@ -81,8 +81,8 @@ - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} @@ -104,8 +104,8 @@ - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} diff --git a/common/socket/pom.xml b/common/socket/pom.xml index fd372809442..af0096ac6ad 100644 --- a/common/socket/pom.xml +++ b/common/socket/pom.xml @@ -71,8 +71,8 @@ true - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} @@ -94,8 +94,8 @@ - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} diff --git a/common/tls/pom.xml b/common/tls/pom.xml index 783d81f50b7..c00431e8440 100644 --- a/common/tls/pom.xml +++ b/common/tls/pom.xml @@ -81,13 +81,13 @@ - io.helidon.config - helidon-config-metadata-processor + io.helidon.codegen + helidon-codegen-apt ${helidon.version} - io.helidon.codegen - helidon-codegen-apt + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} @@ -104,13 +104,13 @@ - io.helidon.config - helidon-config-metadata-processor + io.helidon.codegen + helidon-codegen-apt ${helidon.version} - io.helidon.codegen - helidon-codegen-apt + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} diff --git a/common/tls/src/main/java/io/helidon/common/tls/TlsConfigBlueprint.java b/common/tls/src/main/java/io/helidon/common/tls/TlsConfigBlueprint.java index 058d1b37425..65a4c50a871 100644 --- a/common/tls/src/main/java/io/helidon/common/tls/TlsConfigBlueprint.java +++ b/common/tls/src/main/java/io/helidon/common/tls/TlsConfigBlueprint.java @@ -240,7 +240,7 @@ static List createTrust(Keys config) { /** * Enabled cipher suites for TLS communication. * - * @return cipher suits to enable, by default (or if list is empty), all available cipher suites + * @return cipher suites to enable, by default (or if list is empty), all available cipher suites * are enabled */ @Option.Configured("cipher-suite") diff --git a/config/config-mp/pom.xml b/config/config-mp/pom.xml index 6eb598e3c5a..1fa5e301a2e 100644 --- a/config/config-mp/pom.xml +++ b/config/config-mp/pom.xml @@ -79,16 +79,36 @@ - io.helidon.config - helidon-config-metadata-processor + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.common.features + helidon-common-features-processor + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.common.features + helidon-common-features-processor + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} diff --git a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/JArray.java b/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/JArray.java deleted file mode 100644 index a71c5193ad8..00000000000 --- a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/JArray.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2021 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.config.metadata.processor; - -import java.io.PrintWriter; -import java.util.LinkedList; -import java.util.List; - -class JArray { - private final List values = new LinkedList<>(); - - public void add(JObject object) { - values.add(object); - } - - public void write(PrintWriter metaWriter) { - metaWriter.write('['); - - for (int i = 0; i < values.size(); i++) { - values.get(i).write(metaWriter); - if (i < (values.size() - 1)) { - metaWriter.write(','); - } - } - - metaWriter.write(']'); - } -} diff --git a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/JObject.java b/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/JObject.java deleted file mode 100644 index 8644a2c8c0c..00000000000 --- a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/JObject.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2021 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.config.metadata.processor; - -import java.io.PrintWriter; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.stream.Collectors; - -class JObject { - private final Map stringValues = new TreeMap<>(); - private final Map booleanValues = new TreeMap<>(); - private final Map> stringListValues = new TreeMap<>(); - private final Map arrayValues = new TreeMap<>(); - - JObject add(String key, String value) { - stringValues.put(key, value); - return this; - } - - JObject add(String key, boolean value) { - booleanValues.put(key, value); - return this; - } - - JObject add(String key, JArray array) { - arrayValues.put(key, array); - return this; - } - - JObject add(String key, List values) { - stringListValues.put(key, values); - return this; - } - - void write(PrintWriter metaWriter) { - metaWriter.write('{'); - AtomicBoolean first = new AtomicBoolean(true); - - stringValues.forEach((key, value) -> { - writeNext(metaWriter, first); - metaWriter.write('\"'); - metaWriter.write(key); - metaWriter.write("\":\""); - metaWriter.write(escape(value)); - metaWriter.write('\"'); - }); - booleanValues.forEach((key, value) -> { - writeNext(metaWriter, first); - metaWriter.write('\"'); - metaWriter.write(key); - metaWriter.write("\":"); - metaWriter.write(String.valueOf(value)); - }); - stringListValues.forEach((key, value) -> { - writeNext(metaWriter, first); - metaWriter.write('\"'); - metaWriter.write(key); - metaWriter.write("\":["); - writeStringList(metaWriter, value); - metaWriter.write(']'); - }); - arrayValues.forEach((key, value) -> { - writeNext(metaWriter, first); - metaWriter.write('\"'); - metaWriter.write(key); - metaWriter.write("\":"); - value.write(metaWriter); - }); - - metaWriter.write('}'); - } - - private void writeStringList(PrintWriter metaWriter, List value) { - metaWriter.write(value.stream() - .map(this::escape) - .map(this::quote) - .collect(Collectors.joining(","))); - } - - private String quote(String value) { - return '"' + value + '"'; - } - - private String escape(String string) { - return string.replaceAll("\n", "\\\\n") - .replaceAll("\"", "\\\\\""); - } - - private void writeNext(PrintWriter metaWriter, AtomicBoolean first) { - if (first.get()) { - first.set(false); - return; - } - metaWriter.write(','); - } -} diff --git a/docs-internal/config-metadata.md b/config/metadata/README.md similarity index 58% rename from docs-internal/config-metadata.md rename to config/metadata/README.md index e677c182d85..7f7ef77e091 100644 --- a/docs-internal/config-metadata.md +++ b/config/metadata/README.md @@ -1,55 +1,111 @@ # Configuration metadata -A new module `helidon-config-metadata` now exists with annotations that can be used in Helidon source code -the document what configuration is used. +Configuration metadata can be obtained from annotations, either of generated builders using `@Prototype.Configured` and `Option.Configured` (defined on `Blueprint` + interfaces), or from annotated builders and types using `@io.helidon.config.metadata.Configured` and related. -These annotations are processed by `helidon-config-metadata-processor`. +Blueprints MUST be annotated with annotations from `io.helidon.builder.api` package (Config metadata annotations will most likely fail on these types). +Other types may be annotated with annotations from `io.helidon.config.metadata` package (Builder API annotations are not supported outside of `Blueprint` interfaces). + +The following modules for handling config metadata exist: + +- `io.helidon.config:helidon-config-metadata`: annotations to add to non-Blueprint types to generate documentation +- `io.helidon.config.metadata:helidon-config-metadata-codegen`: code generator that reads annotations and creates `config-metadata.json` +- `io.helidon.config:helidon-config-metadata-processor`: deprecated processor that does the same as `codegen` above +- `io.helidon.config.metadata:helidon-config-metadata-docs`: code generator that reads `config.metadata.json` and generates Helidon `.adoc` files that are part of Helidon Config reference documentation + +How to handle each task is described below. ## Add metadata to a configurable component +In both cases, you need to add the annotation processor for codegen, and the Config metadata codegen modules to the compiler plugin annotation processor path. +If this is done in Helidon itself (in this repository), the same must be added to compiler plugin dependencies, to correctly organize the reactor (as annotation processor path does not add dependencies that the reactor can see). + +```xml + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + + io.helidon.config.metadata + helidon-config-metadata-codegen + ${helidon.version} + + + + + + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen + ${helidon.version} + + + + + +``` + +### Helidon Builder (Blueprints) + +1. Annotate the `Blueprint` interface with `Prototype.Configured` +2. Annotate configurable methods with `Option.Configured` + +The generated JSON will honor types returned by the option methods, generate configuration keys from the method name (e.g. method `clientAuth` would have configuration key `client-auth`), honor default values, and use method javadocs as a source for description of the option. + +See Javadoc of the annotations to see additional customization options. + +### Helidon Config Metadata (Other types) + +Any type except for `Blueprint` can be annotated with `io.helidon.config.metadata.Configured`, and then options may be added to methods (or to the type itself). +This approach can do less, because it does not always have methods to analyze, but it is attempting to do the similar to what is written above for the Builder API (e.g. if a manually constructed builder setter method is annotated, it will still use the correct type, javadoc etc.). + To add meta configuration: -1. Add the following dependency to your `pom.xml`: +1. Add the following dependency to your `pom.xml` (optional dependency, as it only defines annotations): ```xml io.helidon.config helidon-config-metadata - provided true ``` -2. Add the following compiler plugin configuration to add the annotation processor: - ```xml - - - - org.apache.maven.plugins - maven-compiler-plugin - - true - - - io.helidon.config - helidon-config-metadata-processor - ${helidon.version} - - - - - - - ``` -3. Update the `module-info.java` by adding +2. Update the `module-info.java` by adding ```java requires static io.helidon.config.metadata; ``` -4. Annotate the configured class using `@Configured` - usually the builder class. If there is only a factory method, annotate - the class containing the factory method -5. Annotate builder methods using `@ConfiguredOption` - the type of the parameter will be used as type of the property, provides - full customization using annotation properties -6. In case a factory method is the only one available, annotate it with repeating `@ConfiguredOption` to list all annotations -7. Look at existing examples if in doubt -8. Check the output in `target/classes/META-INF/helidon` to see what was generated +3. Annotate the configured class using `@Configured` - usually the builder class. If there is only a factory method, annotate the class containing the factory method +4. Annotate builder methods using `@ConfiguredOption` - the type of the parameter will be used as type of the property, provides full customization using annotation properties +5. In case a factory method is the only one available, annotate it with repeating `@ConfiguredOption` to list all annotations +6. Look at existing examples if in doubt +7. Check the output in `target/classes/META-INF/helidon` to see what was generated + +## Generate Config Reference Documentation + +There are two ways to do this: + +1. go to the `config/metadata/docs` directory, and run `mvn compile exec:exec` +2. go to the `docs` directory, and run `mvn package -Pconfigdoc` + +In both cases, all dependencies from `all/pom.xml` except for `helidon-logging-log4j` and `helidon-logging-slf4j` are analyzed, and documentation is updated in `docs/src/main/asciidoc/config`. +Please check the output of, as there may be warnings that point out a possible problem (such as a file that exists, but is not backed by any `config-metadata.json`). ## Output file format @@ -178,7 +234,7 @@ Example of a nested configuration option: ``` ### AllowedValue element -Allowed value defines a fixed set of allowed values for a configuration option. +Allowed value defines a fixed set of allowed values for a configuration option. Note that allowed values for `enum` types are automatically generated as long as the enum is in the same module (so we can read its javadoc), otherwise the allowed value is still there, but the description is not provided. ```json { diff --git a/config/metadata/codegen/pom.xml b/config/metadata/codegen/pom.xml new file mode 100644 index 00000000000..4ff4d833322 --- /dev/null +++ b/config/metadata/codegen/pom.xml @@ -0,0 +1,63 @@ + + + + + 4.0.0 + + io.helidon.config + helidon-config-metadata-project + 4.1.0-SNAPSHOT + ../pom.xml + + + io.helidon.config.metadata + helidon-config-metadata-codegen + Helidon Config Metadata Codegen + + + Configuration Metadata Code Generation + + + + + io.helidon.common + helidon-common-types + + + io.helidon.codegen + helidon-codegen + + + io.helidon.metadata + helidon-metadata-hson + + + org.junit.jupiter + junit-jupiter-api + test + + + org.hamcrest + hamcrest-all + test + + + diff --git a/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/ConfigMetadataCodegenExtension.java b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/ConfigMetadataCodegenExtension.java new file mode 100644 index 00000000000..a607ab29e64 --- /dev/null +++ b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/ConfigMetadataCodegenExtension.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2024 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.config.metadata.codegen; + +import java.io.ByteArrayOutputStream; +import java.io.PrintWriter; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Stream; + +import io.helidon.codegen.CodegenContext; +import io.helidon.codegen.RoundContext; +import io.helidon.codegen.spi.CodegenExtension; +import io.helidon.common.types.TypeInfo; +import io.helidon.common.types.TypeName; +import io.helidon.metadata.hson.Hson; + +class ConfigMetadataCodegenExtension implements CodegenExtension { + /* + * Configuration metadata file location. + */ + private static final String META_FILE = "META-INF/helidon/config-metadata.json"; + + private final Set blueprints = new HashSet<>(); + private final Set configMetadata = new HashSet<>(); + // Newly created options as part of this processor run - these will be stored to META_FILE + // map of type name to its configured type + private final Map newOptions = new HashMap<>(); + // map of module name to list of classes that belong to it + private final Map> moduleTypes = new HashMap<>(); + + private final CodegenContext ctx; + + ConfigMetadataCodegenExtension(CodegenContext ctx) { + this.ctx = ctx; + } + + @Override + public void process(RoundContext roundContext) { + // we may have multiple rounds, let's collect what we can + // the type info may change (i.e. we code generate something that is not available in the + // first round) + roundContext.annotatedTypes(ConfigMetadataTypes.CONFIGURED) + .forEach(it -> blueprints.add(it.typeName())); + + roundContext.annotatedTypes(ConfigMetadataTypes.META_CONFIGURED) + .forEach(it -> configMetadata.add(it.typeName())); + } + + @Override + public void processingOver(RoundContext roundContext) { + Stream.concat(typesToProcess(blueprints) + .map(it -> TypeHandlerBuilderApi.create(ctx, it)), + typesToProcess(configMetadata) + .map(it -> TypeHandlerMetaApi.create(ctx, it))) + .map(TypeHandler::handle) + .forEach(it -> { + TypeName targetType = it.targetType(); + newOptions.put(targetType, it.configuredType()); + moduleTypes.computeIfAbsent(it.moduleName(), + ignored -> new ArrayList<>()) + .add(targetType); + }); + + storeMetadata(); + } + + private Stream typesToProcess(Set typeNames) { + return typeNames.stream() + .map(ctx::typeInfo) + .flatMap(Optional::stream); + } + + private void storeMetadata() { + List root = new ArrayList<>(); + + for (var module : moduleTypes.entrySet()) { + String moduleName = module.getKey(); + var types = module.getValue(); + List typeArray = new ArrayList<>(); + types.forEach(it -> newOptions.get(it).write(typeArray)); + root.add(Hson.objectBuilder() + .set("module", moduleName) + .setObjects("types", typeArray) + .build()); + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (PrintWriter w = new PrintWriter(baos, true, StandardCharsets.UTF_8)) { + Hson.Array.create(root).write(w); + } + ctx.filer().writeResource(baos.toByteArray(), META_FILE); + } +} diff --git a/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/ConfigMetadataCodegenProvider.java b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/ConfigMetadataCodegenProvider.java new file mode 100644 index 00000000000..10b41e18717 --- /dev/null +++ b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/ConfigMetadataCodegenProvider.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024 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.config.metadata.codegen; + +import java.util.Set; + +import io.helidon.codegen.CodegenContext; +import io.helidon.codegen.spi.CodegenExtension; +import io.helidon.codegen.spi.CodegenExtensionProvider; +import io.helidon.common.types.TypeName; + +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.CONFIGURED; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.META_CONFIGURED; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.META_OPTION; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.META_OPTIONS; + +/** + * A Java {@link java.util.ServiceLoader} service implementation to add config metadata code generation. + */ +public class ConfigMetadataCodegenProvider implements CodegenExtensionProvider { + /** + * Public constructor required by {@link java.util.ServiceLoader}. + */ + public ConfigMetadataCodegenProvider() { + } + + @Override + public CodegenExtension create(CodegenContext ctx, TypeName generatorType) { + return new ConfigMetadataCodegenExtension(ctx); + } + + @Override + public Set supportedAnnotations() { + return Set.of(META_CONFIGURED, + META_OPTION, + META_OPTIONS, + CONFIGURED); + } +} diff --git a/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/ConfigMetadataTypes.java b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/ConfigMetadataTypes.java new file mode 100644 index 00000000000..76a3939b200 --- /dev/null +++ b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/ConfigMetadataTypes.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2023, 2024 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.config.metadata.codegen; + +import io.helidon.common.types.TypeName; + +final class ConfigMetadataTypes { + static final TypeName DEPRECATED = TypeName.create(Deprecated.class); + /* + Using config metadata + */ + static final TypeName META_CONFIGURED = TypeName.create("io.helidon.config.metadata.Configured"); + static final TypeName META_OPTION = TypeName.create("io.helidon.config.metadata.ConfiguredOption"); + static final TypeName META_OPTIONS = TypeName.create("io.helidon.config.metadata.ConfiguredOptions"); + + /* + Using builder API + */ + static final TypeName COMMON_CONFIG = TypeName.create("io.helidon.common.config.Config"); + static final TypeName CONFIG = TypeName.create("io.helidon.config.Config"); + static final TypeName PROTOTYPE_FACTORY = TypeName.create("io.helidon.builder.api.Prototype.Factory"); + static final TypeName BLUEPRINT = TypeName.create("io.helidon.builder.api.Prototype.Blueprint"); + static final TypeName CONFIGURED = TypeName.create("io.helidon.builder.api.Prototype.Configured"); + static final TypeName PROTOTYPE_PROVIDES = TypeName.create("io.helidon.builder.api.Prototype.Provides"); + static final TypeName DESCRIPTION = TypeName.create("io.helidon.builder.api.Description"); + static final TypeName OPTION_CONFIGURED = TypeName.create("io.helidon.builder.api.Option.Configured"); + static final TypeName OPTION_REQUIRED = TypeName.create("io.helidon.builder.api.Option.Required"); + static final TypeName OPTION_PROVIDER = TypeName.create("io.helidon.builder.api.Option.Provider"); + static final TypeName OPTION_ALLOWED_VALUES = TypeName.create("io.helidon.builder.api.Option.AllowedValues"); + static final TypeName OPTION_ALLOWED_VALUE = TypeName.create("io.helidon.builder.api.Option.AllowedValue"); + static final TypeName OPTION_DEFAULT = TypeName.create("io.helidon.builder.api.Option.Default"); + static final TypeName OPTION_DEFAULT_INT = TypeName.create("io.helidon.builder.api.Option.DefaultInt"); + static final TypeName OPTION_DEFAULT_DOUBLE = TypeName.create("io.helidon.builder.api.Option.DefaultDouble"); + static final TypeName OPTION_DEFAULT_BOOLEAN = TypeName.create("io.helidon.builder.api.Option.DefaultBoolean"); + static final TypeName OPTION_DEFAULT_LONG = TypeName.create("io.helidon.builder.api.Option.DefaultLong"); + static final TypeName OPTION_DEFAULT_METHOD = TypeName.create("io.helidon.builder.api.Option.DefaultMethod"); + static final TypeName OPTION_DEFAULT_CODE = TypeName.create("io.helidon.builder.api.Option.DefaultCode"); + + private ConfigMetadataTypes() { + } +} diff --git a/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/ConfiguredAnnotation.java b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/ConfiguredAnnotation.java new file mode 100644 index 00000000000..bbc472decc6 --- /dev/null +++ b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/ConfiguredAnnotation.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2023, 2024 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.config.metadata.codegen; + +import java.util.List; +import java.util.Optional; +import java.util.function.Predicate; + +import io.helidon.common.types.Annotation; +import io.helidon.common.types.TypeInfo; + +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.CONFIGURED; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.DESCRIPTION; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.PROTOTYPE_PROVIDES; + +record ConfiguredAnnotation(Optional description, + Optional prefix, + List provides, + boolean root, + boolean ignoreBuildMethod) { + + static ConfiguredAnnotation createMeta(Annotation annotation) { + return new ConfiguredAnnotation( + annotation.stringValue("description").filter(Predicate.not(String::isBlank)), + annotation.stringValue("prefix").filter(Predicate.not(String::isBlank)), + toProvidesMeta(annotation), + annotation.booleanValue("root").orElse(false), + annotation.booleanValue("ignoreBuildMethod").orElse(false) + ); + } + + static ConfiguredAnnotation createBuilder(TypeInfo blueprint) { + Optional config = blueprint.findAnnotation(CONFIGURED) + .flatMap(Annotation::stringValue) + .filter(Predicate.not(String::isBlank)); + boolean isRoot = config.isPresent() && blueprint.findAnnotation(CONFIGURED) + .flatMap(it -> it.booleanValue("root")) + .orElse(true); + + return new ConfiguredAnnotation( + blueprint.findAnnotation(DESCRIPTION).flatMap(Annotation::stringValue), + config, + toProvidesBuilder(blueprint), + isRoot, + false + ); + } + + private static List toProvidesBuilder(TypeInfo blueprint) { + return blueprint.findAnnotation(PROTOTYPE_PROVIDES) + .flatMap(Annotation::stringValues) + .stream() + .flatMap(List::stream) + .toList(); + } + + private static List toProvidesMeta(Annotation annotation) { + return annotation.stringValues("provides") + .orElseGet(List::of); + } +} diff --git a/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/ConfiguredOptionData.java b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/ConfiguredOptionData.java new file mode 100644 index 00000000000..9771b8b3702 --- /dev/null +++ b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/ConfiguredOptionData.java @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2023, 2024 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.config.metadata.codegen; + +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import java.util.function.Predicate; + +import io.helidon.codegen.CodegenContext; +import io.helidon.common.types.Annotation; +import io.helidon.common.types.TypeInfo; +import io.helidon.common.types.TypeName; +import io.helidon.common.types.TypedElementInfo; + +import static io.helidon.common.types.ElementKind.ENUM; +import static io.helidon.common.types.ElementKind.ENUM_CONSTANT; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.DEPRECATED; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.DESCRIPTION; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.OPTION_ALLOWED_VALUE; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.OPTION_ALLOWED_VALUES; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.OPTION_CONFIGURED; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.OPTION_DEFAULT; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.OPTION_DEFAULT_BOOLEAN; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.OPTION_DEFAULT_CODE; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.OPTION_DEFAULT_DOUBLE; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.OPTION_DEFAULT_INT; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.OPTION_DEFAULT_LONG; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.OPTION_DEFAULT_METHOD; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.OPTION_PROVIDER; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.OPTION_REQUIRED; +import static io.helidon.config.metadata.codegen.TypeHandlerBase.UNCONFIGURED_OPTION; +import static java.util.function.Predicate.not; + +final class ConfiguredOptionData { + private final List allowedValues = new LinkedList<>(); + + private boolean configured = true; + private String name; + private TypeName type; + private String description; + private boolean required; + private String defaultValue; + private boolean experimental; + private boolean provider; + private boolean deprecated; + private boolean merge; + private String kind = "VALUE"; + private TypeName providerType; + + // create from @ConfiguredOption in config-metadata + static ConfiguredOptionData createMeta(CodegenContext ctx, Annotation option) { + ConfiguredOptionData result = new ConfiguredOptionData(); + + option.booleanValue("configured").ifPresent(result::configured); + option.stringValue("key").filter(not(String::isBlank)).ifPresent(result::name); + option.stringValue("description").filter(not(String::isBlank)).ifPresent(result::description); + option.stringValue().filter(not(UNCONFIGURED_OPTION::equals)).ifPresent(result::defaultValue); + option.booleanValue("experimental").ifPresent(result::experimental); + option.booleanValue("required").ifPresent(result::required); + option.booleanValue("mergeWithParent").ifPresent(result::merge); + option.typeValue("type").ifPresent(result::type); + option.stringValue("kind").ifPresent(result::kind); + option.booleanValue("provider").ifPresent(result::provider); + option.booleanValue("deprecated").ifPresent(result::deprecated); + option.annotationValues("allowedValues") + .or(() -> option.annotationValue("allowedValue").map(List::of)) + .stream() + .flatMap(List::stream) + .map(AllowedValue::create) + .forEach(result::addAllowedValue); + + if (result.allowedValues.isEmpty()) { + // if enum, fill this in + option.getValue("type") + .map(TypeName::create) + .flatMap(ctx::typeInfo) + .filter(it -> it.kind() == ENUM) + .ifPresent(it -> enumAllowedValues(result.allowedValues(), it)); + } + + return result; + } + + // create from Option annotations in builder-api + static ConfiguredOptionData createBuilder(TypedElementInfo element) { + ConfiguredOptionData result = new ConfiguredOptionData(); + + Optional optionConfigured = element.findAnnotation(OPTION_CONFIGURED); + optionConfigured.flatMap(Annotation::stringValue).filter(not(String::isBlank)) + .ifPresent(result::name); + optionConfigured.flatMap(it -> it.booleanValue("merge")) + .ifPresent(result::merge); + + element.findAnnotation(DESCRIPTION).flatMap(Annotation::stringValue).ifPresent(result::description); + element.findAnnotation(OPTION_REQUIRED).ifPresent(it -> result.required(true)); + element.findAnnotation(OPTION_PROVIDER).ifPresent(it -> { + it.typeValue().ifPresent(result::providerType); + result.provider(true); + }); + element.findAnnotation(DEPRECATED).ifPresent(it -> result.deprecated(true)); + element.findAnnotation(OPTION_ALLOWED_VALUES) + .flatMap(Annotation::annotationValues) + .or(() -> element.findAnnotation(OPTION_ALLOWED_VALUE).map(List::of)) + .stream() + .flatMap(List::stream) + .map(AllowedValue::create) + .forEach(result::addAllowedValue); + + Optional defaultValues = element.findAnnotation(OPTION_DEFAULT) + .or(() -> element.findAnnotation(OPTION_DEFAULT_INT)) + .or(() -> element.findAnnotation(OPTION_DEFAULT_BOOLEAN)) + .or(() -> element.findAnnotation(OPTION_DEFAULT_LONG)) + .or(() -> element.findAnnotation(OPTION_DEFAULT_DOUBLE)); + if (defaultValues.isPresent()) { + List strings = defaultValues.get().stringValues().orElseGet(List::of); + result.defaultValue(String.join(", ", strings)); + } else if (element.hasAnnotation(OPTION_DEFAULT_METHOD)) { + Annotation annotation = element.annotation(OPTION_DEFAULT_METHOD); + TypeName type = annotation.typeValue("type") + .filter(Predicate.not(OPTION_DEFAULT_METHOD::equals)) + .or(element::enclosingType) + .orElse(null); + String value = annotation.stringValue().orElse(null); + if (value != null) { + // this should always be true, as it is mandatory + if (type == null) { + result.defaultValue(value + "()"); + } else { + result.defaultValue(type.fqName() + "." + value + "()"); + } + } + } else if (element.hasAnnotation(OPTION_DEFAULT_CODE)) { + element.annotation(OPTION_DEFAULT_CODE).stringValue().ifPresent(result::defaultValue); + } + + return result; + } + + static void enumAllowedValues(List allowedValues, TypeInfo typeInfo) { + typeInfo.elementInfo() + .stream() + .filter(it -> it.kind() == ENUM_CONSTANT) + .forEach(it -> { + allowedValues.add(new AllowedValue(it.elementName(), it.description() + .map(Javadoc::parse) + .orElse(""))); + }); + } + + List allowedValues() { + return allowedValues; + } + + String name() { + return name; + } + + TypeName type() { + return type; + } + + String description() { + return description; + } + + boolean optional() { + return !required; + } + + String defaultValue() { + return defaultValue; + } + + boolean experimental() { + return experimental; + } + + boolean provider() { + return provider; + } + + TypeName providerType() { + return providerType; + } + + boolean deprecated() { + return deprecated; + } + + boolean merge() { + return merge; + } + + String kind() { + return kind; + } + + boolean configured() { + return configured; + } + + void type(TypeName type) { + this.type = type; + } + + void name(String name) { + this.name = name; + } + + void description(String description) { + this.description = description; + } + + void required(boolean required) { + this.required = required; + } + + void defaultValue(String defaultValue) { + this.defaultValue = defaultValue; + } + + void experimental(boolean experimental) { + this.experimental = experimental; + } + + void provider(boolean provider) { + this.provider = provider; + } + + void providerType(TypeName provider) { + this.providerType = provider; + } + + void deprecated(boolean deprecated) { + this.deprecated = deprecated; + } + + void merge(boolean merge) { + this.merge = merge; + } + + void kind(String kind) { + this.kind = kind; + } + + void addAllowedValue(AllowedValue value) { + this.allowedValues.add(value); + } + + void configured(boolean configured) { + this.configured = configured; + } + + static final class AllowedValue { + private String value; + private String description; + + private AllowedValue() { + } + + AllowedValue(String value, String description) { + this.value = value; + this.description = description; + } + + String value() { + return value; + } + + String description() { + return description; + } + + private static AllowedValue create(Annotation annotation) { + AllowedValue result = new AllowedValue(); + + annotation.stringValue().ifPresent(it -> result.value = it); + annotation.stringValue("description").filter(not(String::isBlank)).ifPresent(it -> result.description = it); + + return result; + } + } +} diff --git a/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/ConfiguredType.java b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/ConfiguredType.java new file mode 100644 index 00000000000..64ec47fcc4f --- /dev/null +++ b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/ConfiguredType.java @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2021, 2024 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.config.metadata.codegen; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import io.helidon.common.types.TypeName; +import io.helidon.metadata.hson.Hson; + +final class ConfiguredType { + private final Set allProperties = new HashSet<>(); + private final List producerMethods = new LinkedList<>(); + /* + * The type that is built by a builder, or created using create method. + */ + private final TypeName targetClass; + /* + The type we are processing that has @Configured annotation + */ + private final TypeName annotatedClass; + private final List inherited = new LinkedList<>(); + private final ConfiguredAnnotation configured; + + ConfiguredType(ConfiguredAnnotation configured, TypeName annotatedClass, TypeName targetClass, boolean typeDefinition) { + this.annotatedClass = annotatedClass; + this.targetClass = targetClass; + this.configured = configured; + } + + ConfiguredType addProducer(ProducerMethod producer) { + producerMethods.add(producer); + return this; + } + + ConfiguredType addProperty(ConfiguredProperty property) { + allProperties.add(property); + return this; + } + + List producers() { + return producerMethods; + } + + Set properties() { + return allProperties; + } + + String targetClass() { + return targetClass.fqName(); + } + + String annotatedClass() { + return annotatedClass.fqName(); + } + + boolean standalone() { + return configured.root(); + } + + String prefix() { + return configured.prefix().orElse(null); + } + + void write(List typeArray) { + var typeObject = Hson.Object.builder(); + + typeObject.set("type", targetClass()); + typeObject.set("annotatedType", annotatedClass()); + if (standalone()) { + typeObject.set("standalone", true); + } + configured.prefix().ifPresent(it -> typeObject.set("prefix", it)); + configured.description().ifPresent(it -> typeObject.set("description", it)); + + if (!inherited.isEmpty()) { + typeObject.setStrings("inherits", inherited.stream() + .map(TypeName::fqName) + .toList()); + } + + if (!configured.provides().isEmpty()) { + typeObject.setStrings("provides", configured.provides()); + } + + if (!producerMethods.isEmpty()) { + typeObject.setStrings("producers", producerMethods.stream() + .map(Object::toString) + .collect(Collectors.toList())); + } + + List options = new ArrayList<>(); + for (ConfiguredProperty property : allProperties) { + writeProperty(options, "", property); + } + typeObject.setObjects("options", options); + + typeArray.add(typeObject.build()); + } + + @Override + public String toString() { + return targetClass.fqName(); + } + + void addInherited(TypeName classOrIface) { + inherited.add(classOrIface); + } + + private static String paramsToString(List params) { + return params.stream() + .map(TypeName::resolvedName) + .collect(Collectors.joining(", ")); + } + + private void writeProperty(List optionsBuilder, + String prefix, + ConfiguredProperty property) { + + var optionBuilder = Hson.Object.builder(); + if (property.key() != null && !property.key.isBlank()) { + optionBuilder.set("key", prefix(prefix, property.key())); + } + if (!"java.lang.String".equals(property.type)) { + optionBuilder.set("type", property.type()); + } + optionBuilder.set("description", property.description()); + if (property.defaultValue() != null) { + optionBuilder.set("defaultValue", property.defaultValue()); + } + if (property.experimental) { + optionBuilder.set("experimental", true); + } + if (!property.optional) { + optionBuilder.set("required", true); + } + if (!property.kind().equals("VALUE")) { + optionBuilder.set("kind", property.kind()); + } + if (property.provider) { + optionBuilder.set("provider", true); + optionBuilder.set("providerType", property.providerType.fqName()); + } + if (property.deprecated()) { + optionBuilder.set("deprecated", true); + } + if (property.merge()) { + optionBuilder.set("merge", true); + } + String method = property.builderMethod(); + if (method != null) { + optionBuilder.set("method", method); + } + if (property.configuredType != null) { + String finalPrefix; + if (property.kind().equals("LIST")) { + finalPrefix = prefix(prefix(prefix, property.key()), "*"); + } else { + finalPrefix = prefix(prefix, property.key()); + } + property.configuredType.properties() + .forEach(it -> writeProperty(optionsBuilder, finalPrefix, it)); + } + if (!property.allowedValues.isEmpty()) { + List allowedValues = new ArrayList<>(); + + for (ConfiguredOptionData.AllowedValue allowedValue : property.allowedValues) { + var allowedJson = Hson.Object.builder() + .set("value", allowedValue.value()); + if (!allowedValue.description().isBlank()) { + allowedJson.set("description", allowedValue.description().trim()); + } + allowedValues.add(allowedJson.build()); + } + + optionBuilder.setObjects("allowedValues", allowedValues); + } + + optionsBuilder.add(optionBuilder.build()); + } + + private String prefix(String currentPrefix, String newSuffix) { + if (currentPrefix.isEmpty()) { + return newSuffix; + } + return currentPrefix + "." + newSuffix; + } + + static final class ProducerMethod { + private final boolean isStatic; + private final TypeName owningClass; + private final String methodName; + private final List methodParams; + + ProducerMethod(boolean isStatic, TypeName owningClass, String methodName, List methodParams) { + this.isStatic = isStatic; + this.owningClass = owningClass; + this.methodName = methodName; + this.methodParams = methodParams; + } + + @Override + public String toString() { + return owningClass.fqName() + + "#" + + methodName + "(" + + paramsToString(methodParams) + ")"; + } + } + + static final class ConfiguredProperty { + private final String builderMethod; + private final String key; + private final String description; + private final String defaultValue; + private final String type; + private final boolean experimental; + private final boolean optional; + private final String kind; + private final boolean provider; + private final TypeName providerType; + private final boolean deprecated; + private final boolean merge; + private final List allowedValues; + // if this is a nested type + private ConfiguredType configuredType; + + ConfiguredProperty(String builderMethod, + String key, + String description, + String defaultValue, + TypeName type, + boolean experimental, + boolean optional, + String kind, + boolean provider, + TypeName providerType, + boolean deprecated, + boolean merge, + List allowedValues) { + this.builderMethod = builderMethod; + this.key = key; + this.description = description; + this.defaultValue = defaultValue; + this.type = type.fqName(); + this.experimental = experimental; + this.optional = optional; + this.kind = kind; + this.provider = provider; + this.providerType = providerType == null ? type : providerType; + this.deprecated = deprecated; + this.merge = merge; + this.allowedValues = allowedValues; + } + + String builderMethod() { + return builderMethod; + } + + String key() { + return key; + } + + String description() { + return description; + } + + String defaultValue() { + return defaultValue; + } + + String type() { + return type; + } + + boolean experimental() { + return experimental; + } + + boolean optional() { + return optional; + } + + String kind() { + return kind; + } + + boolean deprecated() { + return deprecated; + } + + boolean merge() { + return merge; + } + + void nestedType(ConfiguredType nested) { + this.configuredType = nested; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ConfiguredProperty that = (ConfiguredProperty) o; + return key.equals(that.key); + } + + @Override + public int hashCode() { + return Objects.hash(key); + } + + @Override + public String toString() { + return key; + } + } +} diff --git a/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/Javadoc.java b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/Javadoc.java new file mode 100644 index 00000000000..027594801a8 --- /dev/null +++ b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/Javadoc.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2024 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.config.metadata.codegen; + +import java.util.regex.Pattern; + +import static io.helidon.codegen.CodegenUtil.capitalize; + +/* +Possible improvements: +- @link - create a proper javadoc reference (i.e. always fully qualified reference), such as: + {@link:io.helidon.common.Type#method(java.lang.String)}, so we can generate a nice reference for docs +- @value - if possible, find the actual value (string, int etc.) and add it as `thevalue` +- @see - create a proper javadoc reference (as for @link) + */ +final class Javadoc { + private static final Pattern JAVADOC_CODE = Pattern.compile("\\{@code (.*?)}"); + private static final Pattern JAVADOC_LINK = Pattern.compile("\\{@link (.*?)}"); + private static final Pattern JAVADOC_LINKPLAIN = Pattern.compile("\\{@linkplain (.*?)}"); + private static final Pattern JAVADOC_VALUE = Pattern.compile("\\{@value (.*?)}"); + private static final Pattern JAVADOC_SEE = Pattern.compile("@see (.*?\n)"); + + private Javadoc() { + } + + /** + * Parses a Javadoc comment (provided as a string) into text that can be used for display/docs of the configuration option. + *

+ * The following steps are done: + *

    + *
  • {@code @param} is stripped from the text
  • + *
  • Any {@code @code} section: the code tag is removed, and surrounded with {@code '}
  • + *
  • Any {@code @link} section: the link tag is removed
  • + *
  • Any {@code @linkplain} section: the linkplain tag is removed
  • + *
  • Any {@code @value} section: the value tag is removed, {code #} is replaced with {@code .}
  • + *
  • Any {@code @see} section: the see tag is removed, prefixed with {@code See}, + * {code #} is replaced with {@code .}
  • + *
  • {@code @return} is stripped from the text, and the first letter is capitalized
  • + *
+ * + * @param docComment "raw" javadoc from the source code + * @return description of the option + */ + static String parse(String docComment) { + if (docComment == null) { + return ""; + } + + String javadoc = docComment; + int index = javadoc.indexOf("@param"); + if (index > -1) { + javadoc = docComment.substring(0, index); + } + // replace all {@code xxx} with 'xxx' + javadoc = JAVADOC_CODE.matcher(javadoc).replaceAll(it -> javadocCode(it.group(1))); + // replace all {@link ...} with just the link + javadoc = JAVADOC_LINK.matcher(javadoc).replaceAll(it -> javadocLink(it.group(1))); + // replace all {@link ...} with just the name + javadoc = JAVADOC_LINKPLAIN.matcher(javadoc).replaceAll(it -> javadocLink(it.group(1))); + // replace all {@value ...} with just the reference + javadoc = JAVADOC_VALUE.matcher(javadoc).replaceAll(it -> javadocValue(it.group(1))); + // replace all {@see ...} with just the reference + javadoc = JAVADOC_SEE.matcher(javadoc).replaceAll(it -> javadocSee(it.group(1))); + + int count = 9; + index = javadoc.indexOf(" @return"); + if (index == -1) { + count = 8; + index = javadoc.indexOf("@return"); + } + if (index > -1) { + javadoc = javadoc.substring(0, index) + capitalize(javadoc.substring(index + count).trim()); + } + + return javadoc.trim(); + } + + private static String javadocSee(String originalValue) { + return "See " + javadocValue(originalValue); + } + + private static String javadocCode(String originalValue) { + return '`' + originalValue + '`'; + } + + private static String javadocLink(String originalValue) { + return javadocValue(originalValue); + } + + private static String javadocValue(String originalValue) { + if (originalValue.startsWith("#")) { + return originalValue.substring(1); + } + return originalValue.replace('#', '.'); + } +} diff --git a/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/OptionType.java b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/OptionType.java new file mode 100644 index 00000000000..c3b94483925 --- /dev/null +++ b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/OptionType.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2024 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.config.metadata.codegen; + +import io.helidon.common.types.TypeName; + +record OptionType(TypeName elementType, String kind) { +} diff --git a/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/TypeHandler.java b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/TypeHandler.java new file mode 100644 index 00000000000..c8b7cadaf98 --- /dev/null +++ b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/TypeHandler.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023, 2024 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.config.metadata.codegen; + +interface TypeHandler { + /** + * Discover all options of the configured type. + */ + TypeHandlerResult handle(); +} diff --git a/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/TypeHandlerBase.java b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/TypeHandlerBase.java new file mode 100644 index 00000000000..236f9b98960 --- /dev/null +++ b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/TypeHandlerBase.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2023, 2024 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.config.metadata.codegen; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.function.Predicate; + +import io.helidon.codegen.CodegenContext; +import io.helidon.common.types.TypeInfo; +import io.helidon.common.types.TypeName; +import io.helidon.common.types.TypedElementInfo; + +import static io.helidon.common.types.ElementKind.ENUM; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.COMMON_CONFIG; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.CONFIG; + +abstract class TypeHandlerBase { + static final String UNCONFIGURED_OPTION = "io.helidon.config.metadata.ConfiguredOption.UNCONFIGURED"; + + private final CodegenContext ctx; + + TypeHandlerBase(CodegenContext ctx) { + this.ctx = ctx; + } + + static Predicate isMine(TypeName type) { + TypeName withoutGenerics = type.genericTypeName(); + return info -> info.enclosingType().map(TypeName::genericTypeName).map(withoutGenerics::equals).orElse(true); + } + + // exactly one parameter - either common config, or Helidon config + static boolean hasConfigParam(TypedElementInfo info) { + List arguments = info.parameterArguments(); + if (arguments.size() != 1) { + return false; + } + TypeName argumentType = arguments.get(0).typeName(); + return CONFIG.equals(argumentType) || COMMON_CONFIG.equals(argumentType); + } + + /* + Method name is camel case (such as maxInitialLineLength) + result is dash separated and lower cased (such as max-initial-line-length). + Note that this same method was created in ConfigUtils in common-config, but since this + module should not have any dependencies in it a copy was left here as well. + */ + static String toConfigKey(String methodName) { + StringBuilder result = new StringBuilder(); + + char[] chars = methodName.toCharArray(); + for (char aChar : chars) { + if (Character.isUpperCase(aChar)) { + if (result.isEmpty()) { + result.append(Character.toLowerCase(aChar)); + } else { + result.append('-') + .append(Character.toLowerCase(aChar)); + } + } else { + result.append(aChar); + } + } + + return result.toString(); + } + + static String javadoc(String docComment) { + return Javadoc.parse(docComment); + } + + String key(TypedElementInfo elementInfo, ConfiguredOptionData configuredOption) { + String name = configuredOption.name(); + if (name == null || name.isBlank()) { + return toConfigKey(elementInfo.elementName()); + } + return name; + } + + String description(TypedElementInfo elementInfo, ConfiguredOptionData configuredOption) { + String desc = configuredOption.description(); + if (desc == null) { + return javadoc(elementInfo.description().orElse(null)); + } + return desc; + } + + String defaultValue(String defaultValue) { + return UNCONFIGURED_OPTION.equals(defaultValue) ? null : defaultValue; + } + + List allowedValues(ConfiguredOptionData configuredOption, TypeName type) { + if (type.equals(configuredOption.type()) || !configuredOption.allowedValues().isEmpty()) { + // this was already processed due to an explicit type defined in the annotation + // or allowed values explicitly configured in annotation + return configuredOption.allowedValues(); + } + return allowedValues(type); + } + + CodegenContext ctx() { + return ctx; + } + + List params(TypedElementInfo info) { + return info.parameterArguments() + .stream() + .map(TypedElementInfo::typeName) + .toList(); + } + + void addInterfaces(ConfiguredType type, TypeInfo typeInfo, TypeName requiredAnnotation) { + for (TypeInfo interfaceInfo : typeInfo.interfaceTypeInfo()) { + if (interfaceInfo.hasAnnotation(requiredAnnotation)) { + type.addInherited(interfaceInfo.typeName()); + } else { + addSuperClasses(type, interfaceInfo, requiredAnnotation); + } + } + } + + void addSuperClasses(ConfiguredType type, TypeInfo typeInfo, TypeName requiredAnnotation) { + Optional foundSuperType = typeInfo.superTypeInfo(); + if (foundSuperType.isEmpty()) { + return; + } + TypeInfo superClass = foundSuperType.get(); + + while (true) { + if (superClass.hasAnnotation(requiredAnnotation)) { + // we only care about the first one. This one should reference its superclass/interfaces + // if they are configured as well + type.addInherited(superClass.typeName()); + return; + } + + foundSuperType = superClass.superTypeInfo(); + if (foundSuperType.isEmpty()) { + return; + } + superClass = foundSuperType.get(); + } + } + + List allowedValuesEnum(ConfiguredOptionData data, TypeInfo enumInfo) { + if (!data.allowedValues().isEmpty()) { + // this was already processed due to an explicit type defined in the annotation + // or allowed values explicitly configured in annotation + return data.allowedValues(); + } + return allowedValuesEnum(enumInfo); + } + + private List allowedValuesEnum(TypeInfo enumInfo) { + List values = new ArrayList<>(); + ConfiguredOptionData.enumAllowedValues(values, enumInfo); + return values; + } + + private List allowedValues(TypeName type) { + return ctx().typeInfo(type) + .filter(it -> it.kind() == ENUM) + .map(this::allowedValuesEnum) + .orElseGet(List::of); + + } +} diff --git a/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/TypeHandlerBuilderApi.java b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/TypeHandlerBuilderApi.java new file mode 100644 index 00000000000..11b94b43380 --- /dev/null +++ b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/TypeHandlerBuilderApi.java @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2023, 2024 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.config.metadata.codegen; + +import java.util.List; +import java.util.Optional; +import java.util.function.Predicate; + +import io.helidon.codegen.CodegenContext; +import io.helidon.codegen.CodegenException; +import io.helidon.codegen.ElementInfoPredicates; +import io.helidon.common.types.TypeInfo; +import io.helidon.common.types.TypeName; +import io.helidon.common.types.TypedElementInfo; + +import static io.helidon.common.types.ElementKind.ENUM; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.BLUEPRINT; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.COMMON_CONFIG; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.CONFIGURED; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.OPTION_CONFIGURED; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.PROTOTYPE_FACTORY; + +/* + * Takes care of blueprints annotated with builder API only. + */ +class TypeHandlerBuilderApi extends TypeHandlerBase implements TypeHandler { + private final TypeInfo blueprint; + private final TypeName blueprintType; + + TypeHandlerBuilderApi(CodegenContext ctx, TypeInfo blueprint) { + super(ctx); + + this.blueprint = blueprint; + this.blueprintType = blueprint.typeName(); + } + + static TypeHandler create(CodegenContext ctx, TypeInfo typeInfo) { + return new TypeHandlerBuilderApi(ctx, typeInfo); + } + + /* + This is always: + - an interface + - uses annotations from builder-api + - return type is the one to use + */ + @Override + public TypeHandlerResult handle() { + TypeName prototype = prototype(blueprintType); + TypeName builderType = TypeName.builder(prototype) + .className("Builder") + .addEnclosingName(prototype.className()) + .build(); + TypeName targetType = targetType(blueprint, prototype); + String module = blueprint.module().orElse("unknown"); + + ConfiguredAnnotation configured = ConfiguredAnnotation.createBuilder(blueprint); + + ConfiguredType type = new ConfiguredType(configured, + prototype, + targetType, + true); + + addInterfaces(type, blueprint, CONFIGURED); + + type.addProducer(new ConfiguredType.ProducerMethod(true, prototype, "create", List.of(COMMON_CONFIG))); + type.addProducer(new ConfiguredType.ProducerMethod(true, prototype, "builder", List.of())); + + if (!targetType.equals(prototype)) { + // target type may not have the method (if it is for example PrivateKey) + type.addProducer(new ConfiguredType.ProducerMethod(false, targetType, "create", List.of(prototype))); + } + + // and now process all blueprint methods - must be non default, non static + // methods on this interface + + blueprint.elementInfo() + .stream() + .filter(ElementInfoPredicates::isMethod) + .filter(TypeHandlerBase.isMine(blueprint.typeName())) + .filter(Predicate.not(ElementInfoPredicates::isStatic)) + .filter(Predicate.not(ElementInfoPredicates::isDefault)) + .filter(ElementInfoPredicates.hasAnnotation(OPTION_CONFIGURED)) + .forEach(it -> processBlueprintMethod(builderType, + type, + it)); + + return new TypeHandlerResult(targetType, + module, + type); + } + + @Override + void addInterfaces(ConfiguredType type, TypeInfo typeInfo, TypeName requiredAnnotation) { + for (TypeInfo interfaceInfo : typeInfo.interfaceTypeInfo()) { + if (interfaceInfo.hasAnnotation(requiredAnnotation)) { + TypeName ifaceTypeName = interfaceInfo.typeName(); + + if (interfaceInfo.hasAnnotation(BLUEPRINT)) { + String className = ifaceTypeName.className(); + if (className.endsWith("Blueprint")) { + className = className.substring(0, className.length() - "Blueprint".length()); + } + ifaceTypeName = TypeName.builder(ifaceTypeName) + .className(className) + .build(); + } + + type.addInherited(ifaceTypeName); + } else { + addSuperClasses(type, interfaceInfo, requiredAnnotation); + } + } + } + + private static TypeName prototype(TypeName blueprintType) { + String className = blueprintType.className(); + if (className.endsWith("Blueprint")) { + className = className.substring(0, className.length() - "Blueprint".length()); + } + return TypeName.builder(blueprintType) + .className(className) + .build() + .genericTypeName(); + } + + // if the type implements `Factory`, we want to return X, otherwise "pure" config object + private static TypeName targetType(TypeInfo blueprint, TypeName prototype) { + return blueprint.interfaceTypeInfo() + .stream() + .map(TypeInfo::typeName) + .filter(it -> PROTOTYPE_FACTORY.equals(it.genericTypeName())) + .filter(it -> it.typeArguments().size() == 1) + .map(it -> it.typeArguments().get(0)) + .findAny() + .orElse(prototype); + } + + private OptionType typeForBlueprintFromSignature(TypedElementInfo element, + ConfiguredOptionData annotation) { + // guess from method + + if (!ElementInfoPredicates.hasNoArgs(element)) { + throw new CodegenException("Method " + element + " is annotated with @Configured, " + + "yet it has a parameter. Interface methods must not have parameters.", + element.originatingElement().orElse(element.elementName())); + } + + TypeName returnType = element.typeName(); + if (ElementInfoPredicates.isVoid(element)) { + throw new CodegenException("Method " + element + " is annotated with @Configured, " + + "yet it is void. Interface methods must return the property type.", + element.originatingElement().orElse(element.elementName())); + } + + if (returnType.isOptional()) { + // may be an optional of list etc. + if (!(returnType.isMap() || returnType.isSet() || returnType.isList())) { + return new OptionType(returnType.typeArguments().get(0), "VALUE"); + } + returnType = returnType.typeArguments().get(0); + } + + if (returnType.isList() || returnType.isSet()) { + return new OptionType(returnType.typeArguments().get(0), "LIST"); + } + + if (returnType.isMap()) { + return new OptionType(returnType.typeArguments().get(1), "MAP"); + } + + return new OptionType(returnType.boxed(), annotation.kind()); + } + + private void processBlueprintMethod(TypeName typeName, ConfiguredType configuredType, TypedElementInfo elementInfo) { + // we always have exactly one option per method + ConfiguredOptionData data = ConfiguredOptionData.createBuilder(elementInfo); + + String name = key(elementInfo, data); + String description = description(elementInfo, data); + String defaultValue = defaultValue(data.defaultValue()); + boolean experimental = data.experimental(); + OptionType type = typeForBlueprintFromSignature(elementInfo, data); + boolean optional = defaultValue != null || data.optional(); + boolean deprecated = data.deprecated(); + + Optional enumType = ctx().typeInfo(type.elementType()) + .filter(it -> it.kind() == ENUM); + + List allowedValues; + + if (enumType.isPresent() && defaultValue != null) { + // prefix the default value with the enum name to make it more readable + defaultValue = type.elementType().className() + "." + defaultValue; + allowedValues = allowedValuesEnum(data, enumType.get()); + } else { + allowedValues = allowedValues(data, type.elementType()); + } + + List paramTypes = List.of(elementInfo.typeName()); + + ConfiguredType.ProducerMethod builderMethod = new ConfiguredType.ProducerMethod(false, + typeName, + elementInfo.elementName(), + paramTypes); + + ConfiguredType.ConfiguredProperty property = new ConfiguredType.ConfiguredProperty(builderMethod.toString(), + name, + description, + defaultValue, + type.elementType(), + experimental, + optional, + type.kind(), + data.provider(), + data.providerType(), + deprecated, + data.merge(), + allowedValues); + configuredType.addProperty(property); + } + +} diff --git a/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/TypeHandlerMetaApi.java b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/TypeHandlerMetaApi.java new file mode 100644 index 00000000000..aaf0587ae7c --- /dev/null +++ b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/TypeHandlerMetaApi.java @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2023, 2024 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.config.metadata.codegen; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.function.BiFunction; +import java.util.function.Predicate; + +import io.helidon.codegen.CodegenContext; +import io.helidon.codegen.CodegenException; +import io.helidon.codegen.ElementInfoPredicates; +import io.helidon.common.types.Annotation; +import io.helidon.common.types.TypeInfo; +import io.helidon.common.types.TypeName; +import io.helidon.common.types.TypeNames; +import io.helidon.common.types.TypedElementInfo; +import io.helidon.config.metadata.codegen.ConfiguredType.ProducerMethod; + +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.COMMON_CONFIG; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.CONFIG; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.META_CONFIGURED; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.META_OPTION; +import static io.helidon.config.metadata.codegen.ConfigMetadataTypes.META_OPTIONS; + +/* + * Takes care of blueprints annotated with builder API only. + */ +class TypeHandlerMetaApi extends TypeHandlerBase implements TypeHandler { + private final TypeInfo typeInfo; + private final TypeName typeName; + + TypeHandlerMetaApi(CodegenContext ctx, TypeInfo typeInfo) { + super(ctx); + + this.typeInfo = typeInfo; + this.typeName = typeInfo.typeName(); + } + + public static TypeHandler create(CodegenContext ctx, TypeInfo typeInfo) { + return new TypeHandlerMetaApi(ctx, typeInfo); + } + + @Override + public TypeHandlerResult handle() { + TypeInfo targetType; + boolean isBuilder; + String module; + Optional foundTarget = findBuilderTarget(new HashSet<>(), typeInfo); + ConfiguredAnnotation configured = ConfiguredAnnotation.createMeta(typeInfo.annotation(META_CONFIGURED)); + if (!configured.ignoreBuildMethod() + && foundTarget.isPresent()) { + // we want this both for abstract types and implementations + // this is a builder, we need the target type Builder + TypeName targetTypeName = foundTarget.get(); + targetType = ctx().typeInfo(targetTypeName, ElementInfoPredicates::isMethod) + .orElseThrow(() -> new IllegalStateException("Cannot find target type info for type " + + targetTypeName.fqName() + + ", discovered for type: " + typeInfo.typeName() + .fqName())); + isBuilder = true; + module = targetType.module().orElse("unknown"); + } else { + targetType = typeInfo; + isBuilder = false; + module = typeInfo.module().orElse("unknown"); + } + + /* + now we know whether this is + - a builder + known target class (result of builder() method) + - a standalone class (probably with public static create(Config) method) + - an interface/abstract class only used for inheritance + */ + ConfiguredType type = new ConfiguredType(configured, + typeName, + targetType.typeName(), + false); + + /* + we also need to know all superclasses / interfaces that are configurable so we can reference them + these may be from other modules, so we cannot create a single set of values from all types + */ + addSuperClasses(type, typeInfo, META_CONFIGURED); + addInterfaces(type, typeInfo, META_CONFIGURED); + + if (isBuilder) { + // builder + processBuilderType(typeInfo, type, typeName, targetType); + } else { + // standalone class with create method(s), or interface/abstract class + processTargetType(typeInfo, type, typeName, type.standalone()); + } + + return new TypeHandlerResult(targetType.typeName(), module, type); + } + + List findConfiguredOptionAnnotations(TypedElementInfo elementInfo) { + if (elementInfo.hasAnnotation(META_OPTIONS)) { + Annotation metaOptions = elementInfo.annotation(META_OPTIONS); + return metaOptions.annotationValues() + .stream() + .flatMap(List::stream) + .map(it -> ConfiguredOptionData.createMeta(ctx(), it)) + .toList(); + } + + if (elementInfo.hasAnnotation(META_OPTION)) { + Annotation metaOption = elementInfo.annotation(META_OPTION); + return List.of(ConfiguredOptionData.createMeta(ctx(), metaOption)); + } + + return List.of(); + } + + void processBuilderMethod(TypeName typeName, + ConfiguredType configuredType, + TypedElementInfo elementInfo, + BiFunction optionTypeMethod, + BiFunction> builderParamsMethod) { + List options = findConfiguredOptionAnnotations(elementInfo); + if (options.isEmpty()) { + return; + } + + for (ConfiguredOptionData data : options) { + if (!data.configured()) { + continue; + } + String name = key(elementInfo, data); + String description = description(elementInfo, data); + String defaultValue = defaultValue(data.defaultValue()); + boolean experimental = data.experimental(); + OptionType type = optionTypeMethod.apply(elementInfo, data); + boolean optional = defaultValue != null || data.optional(); + boolean deprecated = data.deprecated(); + List allowedValues = allowedValues(data, type.elementType()); + + List paramTypes = builderParamsMethod.apply(elementInfo, type); + + ProducerMethod builderMethod = new ProducerMethod(false, + typeName, + elementInfo.elementName(), + paramTypes); + + ConfiguredType.ConfiguredProperty property = new ConfiguredType.ConfiguredProperty(builderMethod.toString(), + name, + description, + defaultValue, + type.elementType(), + experimental, + optional, + type.kind(), + data.provider(), + data.providerType(), + deprecated, + data.merge(), + allowedValues); + configuredType.addProperty(property); + } + } + + // annotated type or type methods (not a builder) + private void processTargetType(TypeInfo typeInfo, ConfiguredType type, TypeName typeName, boolean standalone) { + // go through all methods, find all create methods and create appropriate configured producers for them + // if there is a builder, add the builder producer as well + + List methods = typeInfo.elementInfo() + .stream() + .filter(ElementInfoPredicates::isMethod) + // public, package local or protected + .filter(Predicate.not(ElementInfoPredicates::isPrivate)) + // static + .filter(ElementInfoPredicates::isStatic) + .toList(); + + // either this is a target class (such as an interface with create method) + // or this is an interface/abstract class inherited by builders + boolean isTargetType = false; + List validMethods = new LinkedList<>(); + TypedElementInfo configCreator = null; + + // now we have just public static methods, let's look for create/builder + for (TypedElementInfo method : methods) { + String name = method.elementName(); + + if ("create".equals(name)) { + if (method.typeName().genericTypeName().equals(typeName.genericTypeName())) { + validMethods.add(method); + List parameters = method.parameterArguments(); + if (parameters.size() == 1) { + TypeName paramType = parameters.get(0).typeName(); + if (paramType.equals(CONFIG) || paramType.equals(COMMON_CONFIG)) { + configCreator = method; + } + } + isTargetType = true; + } + } else if (name.equals("builder")) { + throw new CodegenException("Type " + typeName.fqName() + " is marked with @Configured" + + ", yet it has a static builder() method. Please mark the builder instead " + + "of this class.", + typeInfo.originatingElement().orElseGet(typeInfo::typeName)); + } + } + + if (isTargetType) { + if (configCreator != null) { + type.addProducer(new ProducerMethod(true, + typeName, + configCreator.elementName(), + params(configCreator))); + } + + // now let's find all methods with @ConfiguredOption + for (TypedElementInfo validMethod : validMethods) { + List options = findConfiguredOptionAnnotations(validMethod); + + if (options.isEmpty()) { + continue; + } + + for (ConfiguredOptionData data : options) { + if ((data.name() == null || data.name().isBlank()) && !data.merge()) { + throw new CodegenException("ConfiguredOption on " + typeName.fqName() + "." + + validMethod + + " does not have value defined. It is mandatory on non-builder " + + "methods", + typeInfo.originatingElement().orElseGet(typeInfo::typeName)); + } + + if (data.description() == null || data.description().isBlank()) { + throw new CodegenException("ConfiguredOption on " + typeName.fqName() + "." + validMethod + + " does not have description defined. It is mandatory on non-builder " + + "methods", + typeInfo.originatingElement().orElseGet(typeInfo::typeName)); + } + + if (data.type() == null) { + // this is the default value + data.type(TypeNames.STRING); + } + + ConfiguredType.ConfiguredProperty prop = new ConfiguredType.ConfiguredProperty(null, + data.name(), + data.description(), + data.defaultValue(), + data.type(), + data.experimental(), + data.optional(), + data.kind(), + data.provider(), + data.providerType(), + data.deprecated(), + data.merge(), + data.allowedValues()); + type.addProperty(prop); + } + } + } else { + // this must be a class/interface used by other classes to extend, so we care about all builder style + // methods + if (standalone) { + throw new CodegenException("Type " + typeName.fqName() + " is marked as standalone configuration unit, " + + "yet it does have " + + "neither a builder method, nor a create method", + typeInfo.originatingElement().orElseGet(typeInfo::typeName)); + } + + typeInfo.elementInfo() + .stream() + .filter(ElementInfoPredicates::isMethod) // methods + .filter(Predicate.not(ElementInfoPredicates::isPrivate)) // public, package or protected + .filter(Predicate.not(ElementInfoPredicates::isStatic)) // not static + .filter(TypeHandlerMetaApi.isMine(typeName)) // declared on this type + .forEach(it -> processBuilderMethod(typeName, type, it)); + } + } + + // annotated builder methods + private void processBuilderType(TypeInfo typeInfo, ConfiguredType type, TypeName typeName, TypeInfo targetType) { + type.addProducer(new ProducerMethod(false, typeName, "build", List.of())); + + TypeName targetTypeName = targetType.typeName(); + // check if static TargetType create(Config) exists + if (targetType.elementInfo() + .stream() + .filter(ElementInfoPredicates::isMethod) + .filter(ElementInfoPredicates::isStatic) + .filter(Predicate.not(ElementInfoPredicates::isPrivate)) + .filter(ElementInfoPredicates.elementName("create")) + .filter(TypeHandlerMetaApi::hasConfigParam) + .anyMatch(TypeHandlerMetaApi.isMine(targetTypeName))) { + + type.addProducer(new ProducerMethod(true, + targetTypeName, + "create", + List.of(COMMON_CONFIG))); + } + + // find all public methods annotated with @ConfiguredOption + typeInfo.elementInfo() + .stream() + .filter(ElementInfoPredicates::isMethod) // methods + .filter(Predicate.not(ElementInfoPredicates::isPrivate)) // not private + .filter(TypeHandlerMetaApi.isMine(typeName)) // declared on this type + .filter(it -> it.hasAnnotation(META_OPTION) || it.hasAnnotation(META_OPTIONS)) + .forEach(it -> processBuilderMethod(typeName, type, it)); + } + + private List builderMethodParams(TypedElementInfo elementInfo, OptionType type) { + return params(elementInfo); + } + + private void processBuilderMethod(TypeName typeName, ConfiguredType configuredType, TypedElementInfo elementInfo) { + processBuilderMethod(typeName, configuredType, elementInfo, this::optionType, this::builderMethodParams); + } + + private OptionType optionType(TypedElementInfo elementInfo, ConfiguredOptionData annotation) { + if (annotation.type() == null || annotation.type().equals(META_OPTION)) { + // guess from method + + List parameters = elementInfo.parameterArguments(); + if (parameters.size() != 1) { + throw new CodegenException("Method " + elementInfo.elementName() + + " is annotated with @ConfiguredOption, " + + "yet it does not have explicit type, or exactly one parameter", + typeInfo.originatingElement().orElseGet(typeInfo::typeName)); + } else { + TypedElementInfo parameter = parameters.iterator().next(); + TypeName paramType = parameter.typeName(); + + if (paramType.isList() || paramType.isSet()) { + return new OptionType(paramType.typeArguments().get(0), "LIST"); + } + + if (paramType.isMap()) { + return new OptionType(paramType.typeArguments().get(1), "MAP"); + } + + return new OptionType(paramType.boxed(), annotation.kind()); + } + + } else { + // use the one defined on annotation + return new OptionType(annotation.type(), annotation.kind()); + } + } + + private Optional findBuilderTarget(Set processed, TypeInfo typeInfo) { + // non-private build method exists that has no parameters, not static, and returns a type + return typeInfo.elementInfo() + .stream() + .filter(ElementInfoPredicates::isMethod) + .filter(Predicate.not(ElementInfoPredicates::isStatic)) + .filter(ElementInfoPredicates::hasNoArgs) + .filter(ElementInfoPredicates.elementName("build")) + .filter(Predicate.not(ElementInfoPredicates::isVoid)) + .filter(Predicate.not(ElementInfoPredicates::isPrivate)) + .findFirst() + .map(it -> it.typeName()); + } +} diff --git a/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/TypeHandlerResult.java b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/TypeHandlerResult.java new file mode 100644 index 00000000000..555ae30122b --- /dev/null +++ b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/TypeHandlerResult.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023, 2024 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.config.metadata.codegen; + +import io.helidon.common.types.TypeName; + +/** + * Result of annotation processing. + * + * @param targetType type that is configured (result of the builder, runtime type of a prototype) + * @param moduleName module of the type + * @param configuredType collected configuration metadata + */ +record TypeHandlerResult(TypeName targetType, + String moduleName, + ConfiguredType configuredType) { +} diff --git a/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/package-info.java b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/package-info.java new file mode 100644 index 00000000000..9883931f32b --- /dev/null +++ b/config/metadata/codegen/src/main/java/io/helidon/config/metadata/codegen/package-info.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024 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. + */ + +/** + * Codegen for Helidon Config Metadata. + *

+ * The code generator triggers on both Helidon Builder configuration annotations, and on + * Helidon Config Metadata configuration annotations. + *

+ * This codegen generates a {@code META-INF/helidon/config-metadata.json} for configuration options in the module. + */ +package io.helidon.config.metadata.codegen; diff --git a/config/metadata/codegen/src/main/java/module-info.java b/config/metadata/codegen/src/main/java/module-info.java new file mode 100644 index 00000000000..560665638ae --- /dev/null +++ b/config/metadata/codegen/src/main/java/module-info.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024 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. + */ + +/** + * Codegen for Helidon Config Metadata. + * + * @see io.helidon.config.metadata.codegen + */ +module io.helidon.config.metadata.codegen { + requires io.helidon.codegen; + requires io.helidon.metadata.hson; + + exports io.helidon.config.metadata.codegen; + + provides io.helidon.codegen.spi.CodegenExtensionProvider + with io.helidon.config.metadata.codegen.ConfigMetadataCodegenProvider; +} \ No newline at end of file diff --git a/config/metadata/docs/etc/spotbugs/exclude.xml b/config/metadata/docs/etc/spotbugs/exclude.xml new file mode 100644 index 00000000000..942fcbc4aa4 --- /dev/null +++ b/config/metadata/docs/etc/spotbugs/exclude.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + diff --git a/config/metadata/docs/pom.xml b/config/metadata/docs/pom.xml new file mode 100644 index 00000000000..92cd3e974f3 --- /dev/null +++ b/config/metadata/docs/pom.xml @@ -0,0 +1,145 @@ + + + + + 4.0.0 + + io.helidon.config + helidon-config-metadata-project + 4.1.0-SNAPSHOT + + + io.helidon.config.metadata + helidon-config-metadata-docs + Helidon Config Metadata Docs + + Generator of Helidon documentation for config metadata (uses the `config-metadata.json` generated by the + `helidon-config-metadata-codegen` module + + + + io.helidon.config.metadata.docs.Main + + true + true + true + true + etc/spotbugs/exclude.xml + + + + + jakarta.json.bind + jakarta.json.bind-api + + + io.helidon.logging + helidon-logging-common + + + com.github.jknack + handlebars + + + org.eclipse + yasson + + + org.slf4j + slf4j-jdk14 + runtime + + + + org.mockito + mockito-core + runtime + + + org.junit.jupiter + junit-jupiter-api + test + + + org.hamcrest + hamcrest-all + test + + + + + io.helidon + helidon-all + pom + runtime + + + io.helidon.logging + helidon-logging-slf4j + + + io.helidon.logging + helidon-logging-log4j + + + + + + + + + + org.antlr + antlr4-runtime + 4.10.1 + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + -proc:none + + + + org.codehaus.mojo + exec-maven-plugin + + java + true + + -classpath + + ${mainClass} + + + + + + diff --git a/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/CmAllowedValue.java b/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/CmAllowedValue.java new file mode 100644 index 00000000000..288f58ff80e --- /dev/null +++ b/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/CmAllowedValue.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2024 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.config.metadata.docs; + +/** + * JSON-B type for Allowed values in config-metadata.json. + */ +public class CmAllowedValue { + private String value; + private String description; + + /** + * Required constructor. + */ + public CmAllowedValue() { + } + + /** + * Required getter. + * + * @return allowed value + */ + public String getValue() { + return value; + } + + /** + * Required setter. + * + * @param value allowed value + */ + public void setValue(String value) { + this.value = value; + } + + /** + * Required getter. + * + * @return description of the allowed value + */ + public String getDescription() { + return description; + } + + /** + * Required setter. + * + * @param description allowed value description + */ + public void setDescription(String description) { + this.description = description; + } +} diff --git a/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/CmModule.java b/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/CmModule.java new file mode 100644 index 00000000000..602a44bad09 --- /dev/null +++ b/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/CmModule.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2024 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.config.metadata.docs; + +import java.util.List; + +/** + * JSON-B type for module in config-metadata.json. + */ +public class CmModule { + private String module; + private List types; + + /** + * Required constructor. + */ + public CmModule() { + } + + /** + * Required getter. + * + * @return module name + */ + public String getModule() { + return module; + } + + /** + * Required setter. + * + * @param module module name + */ + public void setModule(String module) { + this.module = module; + } + + /** + * Required getter. + * + * @return configured types in this module + */ + public List getTypes() { + return types; + } + + /** + * Required setter. + * + * @param types configured types in this module + */ + public void setTypes(List types) { + this.types = types; + } +} diff --git a/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/CmOption.java b/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/CmOption.java new file mode 100644 index 00000000000..c8732aa0478 --- /dev/null +++ b/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/CmOption.java @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2024 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.config.metadata.docs; + +import java.util.List; + +/** + * JSON-B type for configured option in config-metadata.json. + */ +public class CmOption { + private String key; + private String description; + private String method; + private String type = "string"; + private String defaultValue; + private boolean required = false; + private boolean experimental = false; + private boolean deprecated = false; + private boolean provider = false; + private String providerType; + private boolean merge = false; + private Kind kind = Kind.VALUE; + private String refType; + private List allowedValues; + + /** + * Required constructor. + */ + public CmOption() { + } + + /** + * Required getter. + * + * @return list of allowed values of this option + */ + public List getAllowedValues() { + return allowedValues; + } + + /** + * Required setter. + * + * @param allowedValues allowed values + */ + public void setAllowedValues(List allowedValues) { + this.allowedValues = allowedValues; + } + + /** + * Required getter. + * + * @return option kind + */ + public Kind getKind() { + return kind; + } + + /** + * Required setter. + * + * @param kind option kind + */ + public void setKind(Kind kind) { + this.kind = kind; + } + + /** + * Required getter. + * + * @return option config key + */ + public String getKey() { + return key; + } + + /** + * Required setter. + * + * @param key config key + */ + public void setKey(String key) { + this.key = key; + } + + /** + * Required getter. + * + * @return option description + */ + public String getDescription() { + return description; + } + + /** + * Required setter. + * + * @param description option description + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * Required getter. + * + * @return option method + */ + public String getMethod() { + return method; + } + + /** + * Required setter. + * + * @param method option method + */ + public void setMethod(String method) { + this.method = method; + } + + /** + * Required getter. + * + * @return option type + */ + public String getType() { + return type; + } + + /** + * Required setter. + * + * @param type option type + */ + public void setType(String type) { + this.type = type; + } + + /** + * Required getter. + * + * @return option default value + */ + public String getDefaultValue() { + return defaultValue; + } + + /** + * Required setter. + * + * @param defaultValue option default value + */ + public void setDefaultValue(String defaultValue) { + this.defaultValue = defaultValue; + } + + /** + * Required getter. + * + * @return whether this option is required + */ + public boolean isRequired() { + return required; + } + + /** + * Required setter. + * + * @param required option required + */ + public void setRequired(boolean required) { + this.required = required; + } + + /** + * Required getter. + * + * @return whether this option is experimental + */ + public boolean isExperimental() { + return experimental; + } + + /** + * Required setter. + * + * @param experimental whether this option is experimental + */ + public void setExperimental(boolean experimental) { + this.experimental = experimental; + } + + /** + * Required getter. + * + * @return whether this option is deprecated + */ + public boolean isDeprecated() { + return deprecated; + } + + /** + * Required setter. + * + * @param deprecated whether this option is deprecated + */ + public void setDeprecated(boolean deprecated) { + this.deprecated = deprecated; + } + + /** + * Required getter. + * + * @return option refType + */ + public String getRefType() { + return refType; + } + + /** + * Required setter. + * + * @param refType option refType + */ + public void setRefType(String refType) { + this.refType = refType; + } + + /** + * Required getter. + * + * @return whether this option type is a service, and any service implementation may satisfy it + */ + public boolean isProvider() { + return provider; + } + + /** + * Required setter. + * + * @param provider whether this option is a provider + */ + public void setProvider(boolean provider) { + this.provider = provider; + } + + /** + * Required getter. + * + * @return option provider type (service interface) + */ + public String getProviderType() { + return providerType; + } + + /** + * Required setter. + * + * @param providerType option provider type (service interface) + */ + public void setProviderType(String providerType) { + this.providerType = providerType; + } + + /** + * Required getter. + * + * @return whether this option merges child type into this type without a config key + */ + public boolean isMerge() { + return merge; + } + + /** + * Required setter. + * + * @param merge whether to merge this option + */ + public void setMerge(boolean merge) { + this.merge = merge; + } + + @Override + public String toString() { + return key + " (" + type + ")" + (merge ? " merged" : ""); + } + + /** + * Option kind. + */ + public enum Kind { + /** + * Option is a single value (leaf node). + * Example: server port + */ + VALUE, + /** + * Option is a list of values (either primitive, String or object nodes). + * Example: cipher suite in SSL, server sockets + */ + LIST, + /** + * Option is a map of strings to primitive type or String. + * Example: tags in tracing, CDI configuration + */ + MAP + } +} diff --git a/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/CmReference.java b/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/CmReference.java new file mode 100644 index 00000000000..e461a047cc5 --- /dev/null +++ b/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/CmReference.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024 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.config.metadata.docs; + +/** + * Type required for template processing for config reference. + */ +public class CmReference { + private final String file; + private final String title; + + CmReference(String file, String title) { + this.file = file; + this.title = title; + } + + /** + * File name that was generated. + * + * @return file name + */ + public String file() { + return file; + } + + /** + * Title of the file. + * + * @return title + */ + public String title() { + return title; + } +} diff --git a/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/CmType.java b/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/CmType.java new file mode 100644 index 00000000000..783861c4725 --- /dev/null +++ b/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/CmType.java @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2024 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.config.metadata.docs; + +import java.util.List; + +/** + * JSON-B type for configured type in config-metadata.json. + */ +public class CmType { + private String type; + private String title; + private String annotatedType; + private List options; + private String description; + private String prefix; + private boolean standalone; + private List inherits; + private List producers; + private List provides; + private String typeReference; + + /** + * Required constructor. + */ + public CmType() { + } + + /** + * Required getter. + * + * @return type description + */ + public String getDescription() { + return description; + } + + /** + * Required setter. + * + * @param description type description + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * Required getter. + * + * @return type config prefix + */ + public String getPrefix() { + return prefix; + } + + /** + * Required setter. + * + * @param prefix type config prefix + */ + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + /** + * Required getter. + * + * @return whether this is a standalone configuration type + */ + public boolean isStandalone() { + return standalone; + } + + /** + * Required setter. + * + * @param standalone whether this is a standalone configuration type + */ + public void setStandalone(boolean standalone) { + this.standalone = standalone; + } + + /** + * Required getter. + * + * @return list of inherited types + */ + public List getInherits() { + return inherits; + } + + /** + * Required setter. + * + * @param inherits types to inherit + */ + public void setInherits(List inherits) { + this.inherits = inherits; + } + + /** + * Required getter. + * + * @return list of producer methods + */ + public List getProducers() { + return producers; + } + + /** + * Required setter. + * + * @param producers list of producer methods + */ + public void setProducers(List producers) { + this.producers = producers; + } + + /** + * Required getter. + * + * @return type name + */ + public String getType() { + return type; + } + + /** + * Required setter. + * + * @param type type name + */ + public void setType(String type) { + this.type = type; + } + + /** + * Required getter. + * + * @return type that is annotated + */ + public String getAnnotatedType() { + return annotatedType; + } + + /** + * Required setter. + * + * @param annotatedType the annotated type + */ + public void setAnnotatedType(String annotatedType) { + this.annotatedType = annotatedType; + } + + /** + * Required getter. + * + * @return type list of options of this type + */ + public List getOptions() { + return options; + } + + /** + * Required setter. + * + * @param options type options + */ + public void setOptions(List options) { + this.options = options; + } + + /** + * Required getter. + * + * @return type list of provided services + */ + public List getProvides() { + return provides; + } + + /** + * Required setter. + * + * @param provides provided services + */ + public void setProvides(List provides) { + this.provides = provides; + } + + /** + * Whether this type represents a service implementation. + * + * @return whether this type provides an implementation of a service + */ + public boolean hasProvides() { + return provides != null && !provides.isEmpty(); + } + + /** + * Required getter. + * + * @return type reference + */ + public String getTypeReference() { + return typeReference; + } + + /** + * Required setter. + * + * @param typeReference type reference + */ + public void setTypeReference(String typeReference) { + this.typeReference = typeReference; + } + + /** + * Required getter. + * + * @return type title + */ + public String getTitle() { + return title; + } + + /** + * Required setter. + * + * @param title type title + */ + public void setTitle(String title) { + this.title = title; + } + + @Override + public String toString() { + return getType(); + } +} diff --git a/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/ConfigDocs.java b/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/ConfigDocs.java new file mode 100644 index 00000000000..1ed530f5a2f --- /dev/null +++ b/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/ConfigDocs.java @@ -0,0 +1,844 @@ +/* + * Copyright (c) 2024 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.config.metadata.docs; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UncheckedIOException; +import java.lang.System.Logger.Level; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.github.jknack.handlebars.Handlebars; +import com.github.jknack.handlebars.Template; +import com.github.jknack.handlebars.io.URLTemplateSource; +import jakarta.json.bind.Jsonb; +import jakarta.json.bind.JsonbBuilder; +import org.eclipse.yasson.YassonConfig; + +/** + * Entry point to generate config documentation for Helidon Config reference. + *

+ * This module can either be used through {@link io.helidon.config.metadata.docs.Main}, or via this class. + * + * @see #create(java.nio.file.Path) + * @see #process() + */ +public class ConfigDocs { + private static final System.Logger LOGGER = System.getLogger(ConfigDocs.class.getName()); + private static final String CONFIG_REFERENCE_ADOC = "config_reference.adoc"; + private static final String METADATA_JSON_LOCATION = "META-INF/helidon/config-metadata.json"; + private static final String RELATIVE_PATH_ADOC = "{rootdir}/config/"; + private static final Pattern MODULE_PATTERN = Pattern.compile("(.*?)(\\.spi)?\\.([a-zA-Z0-9]*?)"); + private static final Pattern COPYRIGHT_LINE_PATTERN = Pattern.compile(".*Copyright \\(c\\) (.*) Oracle and/or its " + + "affiliates."); + private static final Jsonb JSON_B = JsonbBuilder.create(new YassonConfig().withFailOnUnknownProperties(true)); + private static final Map TYPE_MAPPING; + + static { + Map typeMapping = new HashMap<>(); + typeMapping.put("java.lang.String", "string"); + typeMapping.put("java.lang.Integer", "int"); + typeMapping.put("java.lang.Boolean", "boolean"); + typeMapping.put("java.lang.Long", "long"); + typeMapping.put("java.lang.Character", "char"); + typeMapping.put("java.lang.Float", "float"); + typeMapping.put("java.lang.Double", "double"); + TYPE_MAPPING = Map.copyOf(typeMapping); + } + + private final Path path; + + private ConfigDocs(Path path) { + this.path = path; + } + + /** + * Create a new instance that will update config reference documentation in the {code targetPath}. + * + * @param targetPath path of the config reference documentation, must contain the {@value #CONFIG_REFERENCE_ADOC} + * file, or be empty + * @return new instance of config documentation to call {@link #process()} on + */ + public static ConfigDocs create(Path targetPath) { + return new ConfigDocs(targetPath); + } + + static String titleFromFileName(String fileName) { + String title = fileName; + // string .adoc + if (title.endsWith(".adoc")) { + title = title.substring(0, title.length() - 5); + } + if (title.startsWith("io_helidon_")) { + title = title.substring("io_helidon_".length()); + int i = title.lastIndexOf('_'); + if (i != -1) { + String simpleName = title.substring(i + 1); + String thePackage = title.substring(0, i); + title = simpleName + " (" + thePackage.replace('_', '.') + ")"; + } + } + return title; + } + + // translate HTML to asciidoc + static String translateHtml(String text) { + String result = text; + //

+ result = result.replaceAll("\n\\s*

", "\n"); + result = result.replaceAll("\\s*

", "\n"); + result = result.replaceAll("

", ""); + //
  • + result = result.replaceAll("\\s*
  • \\s*", ""); + result = result.replaceAll("\\s*
\\s*", "\n\n"); + result = result.replaceAll("\\s*\\s*", "\n\n"); + result = result.replaceAll("\n\\s*
    \\s*", "\n"); + result = result.replaceAll("\\s*
      \\s*", "\n"); + result = result.replaceAll("\n\\s*\\s*", "\n"); + result = result.replaceAll("\\s*\\s*", "\n"); + result = result.replaceAll("
    • \\s*", "\n- "); + result = result.replaceAll("\n
      ", "\n"); + result = result.replaceAll("
      \n", "\n"); + result = result.replaceAll("
      ", "\n"); + // also fix javadoc issues + // {@value} + result = result.replaceAll("\\{@value\\s+#?(.*?)}", "`$1`"); + // {@link} + result = result.replaceAll("\\{@link\\s+#?(.*?)}", "`$1`"); + // escaped end of lines + result = result.replaceAll("\\n", "\n"); + // + result = replace(result, "", "", "*", "*"); + // + result = replace(result, "", "", "_", "_"); + // ... + result = replaceLinks(result); + //
      ....
      + result = replacePre(result); + // tables + result = handleTables(result); + //

      ,

      + result = replace(result, "

      ", "

      ", "\n[.underline]#", "#\n"); + result = replace(result, "
      ", "
      ", "\n[.underline]#", "#\n"); + // , + result = replace(result, "", "", "^", "^"); + result = replace(result, "", "", "~", "~"); + + // end of lines followed by a single space (multiple are probably intended) + result = result.replaceAll("\n ", "\n"); + + return result; + } + + /** + * Process the {@code META-INF/helidon/config-metadata.json} files from all dependencies of Helidon, and generate + * config reference documentation for them. + *

      + * The documentation is updated, including copyright years + */ + public void process() { + Path configReference = path.resolve(ConfigDocs.CONFIG_REFERENCE_ADOC); + try { + checkTargetPath(configReference); + } catch (IOException e) { + throw new ConfigDocsException("Failed to check if target path exists and is valid", e); + } + + Handlebars handlebars = new Handlebars(); + Template typeTemplate = template(handlebars, "type-docs.adoc.hbs"); + Template configReferenceTemplate = template(handlebars, "config_reference.adoc.hbs"); + + Enumeration files; + try { + files = ConfigDocs.class.getClassLoader().getResources(METADATA_JSON_LOCATION); + } catch (IOException e) { + throw new ConfigDocsException("Failed to load " + METADATA_JSON_LOCATION + " files from classpath", e); + } + + List allModules = new LinkedList<>(); + + while (files.hasMoreElements()) { + URL url = files.nextElement(); + try { + try (InputStream is = url.openStream()) { + CmModule[] cmModules = JSON_B.fromJson(new InputStreamReader(is, StandardCharsets.UTF_8), CmModule[].class); + allModules.addAll(Arrays.asList(cmModules)); + } + } catch (IOException e) { + LOGGER.log(Level.ERROR, "Failed to process metadata JSON file in: " + url, e); + } + } + + // map of annotated types to documentation + Map configuredTypes = new HashMap<>(); + + for (CmModule module : allModules) { + for (CmType type : module.getTypes()) { + configuredTypes.put(type.getAnnotatedType(), type); + } + } + + // translate HTML in description + translateHtml(configuredTypes); + // add all inherited options to each type + resolveInheritance(configuredTypes); + // add all options from merged types as direct options to each type + resolveMerges(configuredTypes); + // resolve type reference (for javadocs) + resolveTypeReference(configuredTypes); + // add titles (remove io.helidon from package or similar) + addTitle(configuredTypes); + + List generatedFiles = new LinkedList<>(); + for (CmModule module : allModules) { + moduleDocs(configuredTypes, typeTemplate, path, module, generatedFiles); + } + + // sort alphabetically by page title + generatedFiles.sort(Comparator.comparing(ConfigDocs::titleFromFileName)); + + generateConfigReference(configReference, configReferenceTemplate, generatedFiles); + + // and now report obsolete files + // filter out generated files + try (Stream x = Files.list(path) + .filter(it -> it.getFileName().toString().endsWith(".adoc")) + .filter(it -> !it.getFileName().toString().equals(CONFIG_REFERENCE_ADOC)) + .filter(it -> !generatedFiles.contains(String.valueOf(it.getFileName())))) { + x.forEach(it -> LOGGER.log(Level.WARNING, "File " + it.toAbsolutePath() + + " should be deleted, as its config metadata no longer exists")); + } catch (IOException e) { + LOGGER.log(Level.ERROR, "Failed to discover obsolete files in " + path.toAbsolutePath(), e); + } + } + + private static String replacePre(String result) { + // pre - replace with code block + StringBuilder theBuilder = new StringBuilder(); + int lastIndex = 0; + while (true) { + int index = result.indexOf("

      ", lastIndex);
      +            if (index == -1) {
      +                // add the rest of the string
      +                theBuilder.append(result.substring(lastIndex));
      +                break;
      +            }
      +            int endIndex = result.indexOf("
      ", index); + theBuilder.append(result, lastIndex, index); + theBuilder.append("\n----\n"); + theBuilder.append(result, index + 5, endIndex); + theBuilder.append("\n----\n"); + lastIndex = endIndex + 6; + } + return theBuilder.toString(); + } + + private static String handleTables(String result) { + // table - keep as is, just a pass-through + StringBuilder theBuilder = new StringBuilder(); + int lastIndex = 0; + while (true) { + int index = result.indexOf("", index); + theBuilder.append(result, lastIndex, index); + theBuilder.append("\n++++\n"); + theBuilder.append(result, index, endIndex + 8); + theBuilder.append("\n++++\n"); + lastIndex = endIndex + 8; + } + return theBuilder.toString(); + } + + private static String replaceLinks(String result) { + //https://docs.oracle.com/en-us/iaas/Content/API/Concepts/apisigningkey.htm[API Signing Key's fingerprint] + Pattern pattern = Pattern.compile("(.*?)", Pattern.DOTALL); + return pattern.matcher(result).replaceAll(it -> it.group(1) + + "[" + it.group(2) + "]"); + } + + // replaces beginning and ending tags with a string, and removed end of lines in the text within + private static String replace(String source, String start, String end, String newStart, String newEnd) { + Pattern pattern = Pattern.compile(start + "(\\s*)(.*?)(\\s*)" + end, Pattern.DOTALL); + return pattern.matcher(source) + .replaceAll(it -> it.group(1) + + newStart + + it.group(2).replace('\n', ' ') + + newEnd + + it.group(3)); + } + + private static String title(String typeName) { + String title = typeName; + if (title.startsWith("io.helidon.")) { + title = title.substring("io.helidon.".length()); + int i = title.lastIndexOf('.'); + if (i != -1) { + String simpleName = title.substring(i + 1); + String thePackage = title.substring(0, i); + title = simpleName + " (" + thePackage + ")"; + } + } + return title; + } + + private static void moduleDocs(Map configuredTypes, + Template template, + Path modulePath, + CmModule module, + List generatedFiles) { + Function exists = type -> { + // 1: check if part of this processing + if (configuredTypes.containsKey(type)) { + return true; + } + // 2: check if exists in target directory + String path = type.replace('.', '_') + ".adoc"; + return Files.exists(modulePath.resolve(path)); + }; + LOGGER.log(Level.INFO, "Documenting module " + module.getModule()); + // each type will have its own, such as: + // docs/io.helidon.common.configurable/LruCache.adoc + for (CmType type : module.getTypes()) { + try { + generateType(generatedFiles, configuredTypes, template, modulePath, type, exists); + } catch (IOException e) { + LOGGER.log(Level.ERROR, "Failed to generate docs for annotated type: " + type.getAnnotatedType(), e); + } + } + } + + private static void generateType(List generatedFiles, + Map configuredTypes, + Template template, + Path modulePath, + CmType type, + Function exists) throws IOException { + sortOptions(type); + + String fileName = fileName(type.getType()); + Path typePath = modulePath.resolve(fileName); + + boolean sameContent = false; + if (Files.exists(typePath)) { + // check if maybe the file content is not modified + CharSequence current = typeFile(configuredTypes, + template, + type, + exists, + currentCopyrightYears(typePath)); + if (sameContent(typePath, current)) { + sameContent = true; + } + } + + CharSequence fileContent = typeFile(configuredTypes, + template, + type, + exists, + newCopyrightYears(typePath)); + + generatedFiles.add(fileName); + if (!sameContent) { + // Write the target type + Files.writeString(typePath, + fileContent, + StandardOpenOption.TRUNCATE_EXISTING, + StandardOpenOption.CREATE); + } + + if (!type.getAnnotatedType().startsWith(type.getType())) { + // generate two docs, just to make sure we do not have a conflict + // example: Zipkin and Jaeger generate target type io.opentracing.Tracer, yet we need separate documents + fileName = fileName(type.getAnnotatedType()); + Path annotatedTypePath = modulePath.resolve(fileName); + generatedFiles.add(fileName); + if (!sameContent) { + // Write the annotated type (needed for Jaeger & Zipkin that produce the same target) + Files.writeString(annotatedTypePath, + fileContent, + StandardOpenOption.TRUNCATE_EXISTING, + StandardOpenOption.CREATE); + } + } + } + + private static boolean sameContent(Path path, CharSequence current) { + try { + return Files.readString(path).equals(current.toString()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static String fileName(String typeName) { + return typeName.replace('.', '_') + ".adoc"; + } + + private static void sortOptions(CmType type) { + List options = new ArrayList<>(type.getOptions()); + options.sort(Comparator.comparing(CmOption::getKey)); + type.setOptions(options); + } + + private static CharSequence configReferenceFile(Template template, + List generatedFiles, + String copyrightYears) { + List references = new ArrayList<>(); + for (String generatedFile : generatedFiles) { + references.add(new CmReference(generatedFile, + titleFromFileName(generatedFile))); + } + Map context = Map.of("year", copyrightYears, + "data", references); + try { + return template.apply(context); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + private static CharSequence typeFile(Map configuredTypes, + Template template, + CmType type, + Function exists, + String copyrightYears) throws IOException { + boolean hasRequired = false; + boolean hasOptional = false; + for (CmOption option : type.getOptions()) { + if (option.isRequired()) { + hasRequired = true; + } else { + hasOptional = true; + } + option.setRefType(mapType(configuredTypes, option, exists)); + } + + Map context = Map.of("year", copyrightYears, + "hasRequired", hasRequired, + "hasOptional", hasOptional, + "type", type); + return template.apply(context); + } + + private static String newCopyrightYears(Path path) { + String currentYear = String.valueOf(ZonedDateTime.now().getYear()); + + if (Files.exists(path)) { + // get current copyright year + String copyrightYears = currentCopyrightYears(path); + if (copyrightYears == null) { + return currentYear; + } + if (copyrightYears.endsWith(currentYear)) { + return copyrightYears; + } + int index = copyrightYears.indexOf(','); + if (index == -1) { + return copyrightYears + ", " + currentYear; + } + return copyrightYears.substring(0, index) + ", " + currentYear; + } + return currentYear; + } + + private static String currentCopyrightYears(Path path) { + try (var lines = Files.lines(path)) { + return lines.flatMap(line -> { + Matcher matcher = COPYRIGHT_LINE_PATTERN.matcher(line); + if (matcher.matches()) { + return Stream.of(matcher.group(1)); + } + return Stream.empty(); + }) + .findFirst() + .orElse(null); + } catch (IOException e) { + LOGGER.log(Level.WARNING, "Could not discover existing copyright year for " + path.toAbsolutePath(), e); + return null; + } + } + + private static String mapType(Map configuredTypes, + CmOption option, + Function exists) { + String type = option.getType(); + String mapped = TYPE_MAPPING.get(type); + CmOption.Kind kind = option.getKind(); + + String displayType = displayType(kind, mapped == null ? type : mapped); + + if (mapped == null) { + if (option.getAllowedValues() != null && !option.getAllowedValues().isEmpty()) { + return mapAllowedValues(option, displayType); + } + if (option.isProvider()) { + String providerType = option.getProviderType(); + providerType = (providerType == null) ? type : providerType; + StringBuilder typeString = new StringBuilder(byKind(kind, type)); + typeString.append(" (service provider interface)"); + + // let's try to locate available service implementations on classpath + List providers = findProviders(configuredTypes, providerType); + if (!providers.isEmpty()) { + typeString.append("\n\nSuch as:\n\n"); + for (CmType provider : providers) { + String linkText = displayType(CmOption.Kind.VALUE, provider.getType()); + if (provider.getPrefix() != null) { + linkText = provider.getPrefix() + " (" + linkText + ")"; + } + typeString.append(" - ") + .append(toLink(provider.getType(), linkText, exists)); + typeString.append("\n"); + } + typeString.append("\n"); + } + return typeString.toString(); + } + return toLink(type, displayType, exists); + } + return displayType; + } + + private static String toLink(String type, String displayType, Function exists) { + if (type.startsWith("io.helidon")) { + if (type.equals("io.helidon.config.Config") || type.equals("io.helidon.common.config.Config")) { + return "Map<string, string> (documented for specific cases)"; + } + // make sure the file exists + if (exists.apply(type)) { + return "xref:" + ConfigDocs.RELATIVE_PATH_ADOC + type.replace('.', '_') + ".adoc[" + displayType + "]"; + } + } + return displayType; + } + + private static List findProviders(Map configuredTypes, String providerInterface) { + return configuredTypes.values() + .stream() + .filter(it -> it.getProvides() != null) + .filter(it -> it.getProvides().contains(providerInterface)) + .toList(); + } + + private static String displayType(CmOption.Kind kind, String type) { + int lastIndex = type.lastIndexOf('.'); + if (lastIndex == -1) { + return byKind(kind, type); + } + String name = type.substring(lastIndex + 1); + if ("Builder".equals(name)) { + String base = type.substring(0, lastIndex); + lastIndex = base.lastIndexOf('.'); + if (lastIndex == -1) { + // this is a pure Builder class, need to show package to distinguish + return byKind(kind, type); + } else { + return byKind(kind, base.substring(lastIndex + 1) + ".Builder"); + } + } else { + return byKind(kind, name); + } + } + + private static String byKind(CmOption.Kind kind, String type) { + // no dots + return switch (kind) { + case LIST -> type + "[]"; + case MAP -> "Map<string, " + type + ">"; + default -> type; + }; + } + + private static String mapAllowedValues(CmOption option, String displayType) { + List values = option.getAllowedValues(); + + return displayType + + " (" + values.stream().map(CmAllowedValue::getValue).collect(Collectors.joining(", ")) + ")"; + } + + // the target path must either contain zero files, or the config reference + // and it must exist + private void checkTargetPath(Path configReference) throws IOException { + if (Files.exists(path) && Files.isDirectory(path)) { + // either empty, or contains config reference + if (Files.exists(configReference) && Files.isRegularFile(configReference)) { + return; + } + // must be empty + try (Stream stream = Files.list(path)) { + if (stream.findAny() + .isPresent()) { + + throw new ConfigDocsException("Cannot generate config reference documentation, unless target path contains " + + CONFIG_REFERENCE_ADOC + " file or it is empty. " + + "Target path: " + path.toAbsolutePath() + " contains files"); + } + } + } else { + throw new IllegalArgumentException("Target path must be a directory and must exist: " + + path.toAbsolutePath().normalize()); + } + } + + private Template template(Handlebars handlebars, String template) { + URL resource = ConfigDocs.class.getResource(template); + if (resource == null) { + throw new ConfigDocsException("Failed to locate required handlebars template on classpath: " + template); + } + Template typeTemplate; + Template configReferenceTemplate; + try { + return handlebars.compile(new URLTemplateSource(template, resource)); + } catch (IOException e) { + throw new ConfigDocsException("Failed to load handlebars template on classpath: " + template, e); + } + } + + private void generateConfigReference(Path configReference, Template template, List generatedFiles) { + if (Files.exists(configReference)) { + // if content not modified, do not update copyright + CharSequence current = configReferenceFile(template, + generatedFiles, + currentCopyrightYears(configReference)); + if (sameContent(configReference, current)) { + return; + } + } + + CharSequence fileContent = configReferenceFile(template, + generatedFiles, + newCopyrightYears(configReference)); + + try { + LOGGER.log(Level.INFO, "Updating " + configReference.toAbsolutePath()); + Files.writeString(configReference, + fileContent, + StandardOpenOption.TRUNCATE_EXISTING, + StandardOpenOption.CREATE); + } catch (IOException e) { + LOGGER.log(Level.ERROR, "Failed to update " + configReference.toAbsolutePath(), e); + } + } + + private void addTitle(Map configuredTypes) { + for (CmType value : configuredTypes.values()) { + value.setTitle(title(value.getType())); + } + } + + private void resolveTypeReference(Map configuredTypes) { + for (CmType value : configuredTypes.values()) { + value.setTypeReference(resolveTypeReference(value.getType())); + } + } + + private String resolveTypeReference(String type) { + if (type.startsWith("io.helidon")) { + // our type + return resolveModuleFromType(type); + } else { + // no reference + return type; + } + } + + private String resolveModuleFromType(String type) { + Matcher m = MODULE_PATTERN.matcher(type); + if (m.matches()) { + String moduleName = m.group(1); + return "link:{javadoc-base-url}/" + moduleName + "/" + toJavadocLink(type) + "[" + type + "]"; + } + return type; + } + + private String toJavadocLink(String type) { + return type.replace('.', '/') + ".html"; + } + + private void translateHtml(Map configuredTypes) { + for (CmType value : configuredTypes.values()) { + value.getOptions().forEach(this::translateHtml); + } + } + + private void translateHtml(CmOption option) { + String description = option.getDescription(); + description = addAllowedValues(description, option); + description = translateHtml(description); + option.setDescription(description); + } + + private String addAllowedValues(String description, CmOption option) { + List allowedValues = option.getAllowedValues(); + if (allowedValues == null || allowedValues.isEmpty()) { + // no allowed values + return description; + } + if (allowedValues.stream() + .allMatch(it -> it.getDescription() == null || it.getDescription().isBlank())) { + // allowed values, but no description (we should eventually add javadoc link, if we can figure out + // how to locate the URL for it + return description; + } + StringBuilder sb = new StringBuilder("\n\nAllowed values:\n\n"); + for (CmAllowedValue allowedValue : allowedValues) { + sb.append("- `") + .append(allowedValue.getValue()) + .append("`: ") + .append(allowedValue.getDescription()) + .append('\n'); + + } + return description + sb; + } + + private void resolveMerges(Map configuredTypes) { + List remaining = new ArrayList<>(configuredTypes.values()); + Map resolved = new HashMap<>(); + boolean shouldExit = false; + while (!shouldExit) { + shouldExit = true; + + for (int i = 0; i < remaining.size(); i++) { + CmType next = remaining.get(i); + boolean isResolved = true; + List options = next.getOptions(); + for (int j = 0; j < options.size(); j++) { + CmOption option = options.get(j); + String optionType = option.getType(); + if (option.isMerge()) { + // primitives and strings are always resolved + if (!(TYPE_MAPPING.containsKey(optionType) || TYPE_MAPPING.containsValue(optionType))) { + isResolved = false; + if (resolved.containsKey(optionType)) { + options.remove(j); + options.addAll(resolved.get(optionType).getOptions()); + shouldExit = false; + break; + } + } + } + } + + if (isResolved) { + resolved.put(next.getType(), next); + remaining.remove(i); + shouldExit = false; + break; + } + } + } + + if (!remaining.isEmpty()) { + LOGGER.log(Level.WARNING, "There are types with merged type that is not on classpath: "); + for (CmType cmType : remaining) { + for (CmOption option : cmType.getOptions()) { + if (option.isMerge()) { + LOGGER.log(Level.WARNING, " Option " + option.getKey() + ", merges: " + option.getType() + " in " + + cmType.getAnnotatedType()); + } + } + + } + } + } + + private void resolveInheritance(Map configuredTypes) { + Map resolved = new HashMap<>(); + List remaining = new ArrayList<>(configuredTypes.values()); + + boolean didResolve = true; + + while (didResolve) { + didResolve = false; + for (int i = 0; i < remaining.size(); i++) { + CmType next = remaining.get(i); + if (next.getInherits() == null) { + resolved.put(next.getAnnotatedType(), next); + didResolve = true; + remaining.remove(i); + break; + } else { + boolean allExist = true; + for (String inherit : next.getInherits()) { + if (!resolved.containsKey(inherit)) { + allExist = false; + break; + } + } + if (allExist) { + resolveInheritance(resolved, next); + resolved.put(next.getType(), next); + didResolve = true; + remaining.remove(i); + break; + } + } + } + } + + if (!remaining.isEmpty()) { + System.err.println("There are types with inheritance that is not on classpath: "); + for (CmType cmType : remaining) { + System.err.println("Type " + cmType.getType() + ", inherits: " + cmType.getInherits()); + } + } + } + + private void resolveInheritance(Map resolved, CmType next) { + // Allow option info on subclasses or implementations of interfaces to override option info from higher. + Map options = new HashMap<>(); + + List inherits = next.getInherits(); + // Traverse from higher to lower in the inheritance structure so more specific settings take precedence. + ListIterator inheritsIt = inherits.listIterator(inherits.size()); + while (inheritsIt.hasPrevious()) { + resolved.get(inheritsIt.previous()) + .getOptions() + .forEach(inheritedOption -> options.put(inheritedOption.getKey(), inheritedOption)); + } + // Now apply options from the type being processed. + next.getOptions().forEach(opt -> options.put(opt.getKey(), opt)); + next.setOptions(new ArrayList<>(options.values())); + next.setInherits(null); + } +} diff --git a/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/ConfigDocsException.java b/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/ConfigDocsException.java new file mode 100644 index 00000000000..6962b529c0d --- /dev/null +++ b/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/ConfigDocsException.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 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.config.metadata.docs; + +import java.util.Objects; + +/** + * Runtime exception for problems when generating config documentation. + */ +public class ConfigDocsException extends RuntimeException { + /** + * A new exception with customized message. + * + * @param message error message + */ + public ConfigDocsException(String message) { + super(Objects.requireNonNull(message)); + } + + /** + * A new exception with customized message and a cause. + * + * @param message error message + * @param cause cause of this exception + */ + public ConfigDocsException(String message, Throwable cause) { + super(Objects.requireNonNull(message), Objects.requireNonNull(cause)); + } +} diff --git a/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/Main.java b/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/Main.java new file mode 100644 index 00000000000..e8f3085ce71 --- /dev/null +++ b/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/Main.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2024 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.config.metadata.docs; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import io.helidon.logging.common.LogConfig; + +/** + * Main class to start generating config reference documentation. + */ +public final class Main { + static { + LogConfig.initClass(); + } + + private Main() { + } + + /** + * Start generating reference documentation. + * + * @param args either empty (target path is discovered if possible), or a single parameter - the target path to generate docs + * @throws io.helidon.config.metadata.docs.ConfigDocsException in case the path is not correct, or a problem is discovered + * while generating the documentation + */ + public static void main(String[] args) { + LogConfig.configureRuntime(); + + Path targetPath; + + if (args.length == 0) { + targetPath = findReasonablePath(); + } else if (args.length == 1) { + targetPath = Paths.get(args[0]); + } else { + throw new IllegalArgumentException("This tool can have zero or one parameters " + + "(path to generated code). Got " + args.length + " parameters"); + } + + Path path = targetPath.toAbsolutePath().normalize(); + ConfigDocs docs = ConfigDocs.create(path); + docs.process(); + } + + private static Path findReasonablePath() { + Path p = Paths.get("docs/src/main/asciidoc/config"); + if (Files.exists(p) && Files.isDirectory(p)) { + return p; + } + p = Paths.get(".").toAbsolutePath().normalize(); + if (p.toString().replace('\\', '/').endsWith("config/metadata/docs")) { + // we are probably in Helidon repository in config/metadata/docs + return p.resolve("../../../docs/src/main/asciidoc/config"); + } + throw new IllegalArgumentException("Cannot discover config asciidoc path, please provide it as a parameter"); + } +} diff --git a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/package-info.java b/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/package-info.java similarity index 75% rename from config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/package-info.java rename to config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/package-info.java index 50460f37d7c..8371c13f7c2 100644 --- a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/package-info.java +++ b/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Oracle and/or its affiliates. + * Copyright (c) 2024 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. @@ -15,6 +15,6 @@ */ /** - * Annotation processor generating JSON metadata for configuration. + * Generates config documentation ({@code .adoc} files) from the config metadata JSON files. */ -package io.helidon.config.metadata.processor; +package io.helidon.config.metadata.docs; diff --git a/config/metadata/docs/src/main/resources/io/helidon/config/metadata/docs/config_reference.adoc.hbs b/config/metadata/docs/src/main/resources/io/helidon/config/metadata/docs/config_reference.adoc.hbs new file mode 100644 index 00000000000..c2284b2dadd --- /dev/null +++ b/config/metadata/docs/src/main/resources/io/helidon/config/metadata/docs/config_reference.adoc.hbs @@ -0,0 +1,42 @@ +{{! +Copyright (c) 2024 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. +}}/////////////////////////////////////////////////////////////////////////////// + + Copyright (c) {{year}} 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. + +/////////////////////////////////////////////////////////////////////////////// + +ifndef::rootdir[:rootdir: {docdir}/..] +:description: Configuration Reference +:keywords: helidon, config, reference + += Configuration Reference + +The following section lists all configurable types in Helidon. + +{{#each data}}- xref:{rootdir}/config/{{this.file}}[{{this.title}}] +{{/each}} \ No newline at end of file diff --git a/config/metadata/docs/src/main/resources/io/helidon/config/metadata/docs/type-docs.adoc.hbs b/config/metadata/docs/src/main/resources/io/helidon/config/metadata/docs/type-docs.adoc.hbs new file mode 100644 index 00000000000..37d9903f306 --- /dev/null +++ b/config/metadata/docs/src/main/resources/io/helidon/config/metadata/docs/type-docs.adoc.hbs @@ -0,0 +1,86 @@ +{{! +Copyright (c) 2024 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. +}}/////////////////////////////////////////////////////////////////////////////// + + Copyright (c) {{year}} 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. + +/////////////////////////////////////////////////////////////////////////////// + +ifndef::rootdir[:rootdir: {docdir}/..] +:description: Configuration of {{type.type}} +:keywords: helidon, config, {{type.type}} +:basic-table-intro: The table below lists the configuration keys that configure {{type.type}} +include::{rootdir}/includes/attributes.adoc[] + += {{type.title}} Configuration + +// tag::config[] +{{#if type.description}} +{{type.description}} +{{/if}} + +Type: {{type.typeReference}} + +{{#if type.standalone}} +This is a standalone configuration type, prefix from configuration root: `{{type.prefix}}` +{{else if type.prefix}} +[source,text] +.Config key +---- +{{type.prefix}} +---- +{{/if}} + +{{#if type.hasProvides}}This type provides the following service implementations: + +{{#each type.provides}}- `{{this}}` +{{/each}} +{{/if}} +== Configuration options +{{#if hasRequired}} +.Required configuration options +[cols="3,3a,2,5a"] +|=== +|key |type |default value |description + +{{#each type.options}}{{#if this.required}}|{{#if this.deprecated}}[.line-through]#{{/if}}`{{this.key}}`{{#if this.deprecated}}#{{/if}} |{{{this.refType}}} |{{#if this.defaultValue}}`{{this.defaultValue}}`{{else}}{nbsp}{{/if}} |{{#if this.deprecated}}*Deprecated* {{/if}}{{#if this.experimental}}*Experimental* {{/if}}{{{this.description}}} +{{/if}}{{/each}} +|=== +{{/if}} + +{{#if hasOptional}} +.Optional configuration options +[cols="3,3a,2,5a"] + +|=== +|key |type |default value |description + +{{#each type.options}}{{#unless this.required}}|{{#if this.deprecated}}[.line-through]#{{/if}}`{{this.key}}`{{#if this.deprecated}}#{{/if}} |{{{this.refType}}} |{{#if this.defaultValue}}`{{this.defaultValue}}`{{else}}{nbsp}{{/if}} |{{#if this.deprecated}}*Deprecated* {{/if}}{{#if this.experimental}}*Experimental* {{/if}}{{{this.description}}} +{{/unless}}{{/each}} +|=== +{{/if}} +// end::config[] \ No newline at end of file diff --git a/config/metadata/docs/src/main/resources/logging.properties b/config/metadata/docs/src/main/resources/logging.properties new file mode 100644 index 00000000000..2df93352d7b --- /dev/null +++ b/config/metadata/docs/src/main/resources/logging.properties @@ -0,0 +1,21 @@ +# +# Copyright (c) 2024 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. +# + +handlers=java.util.logging.ConsoleHandler +java.util.logging.ConsoleHandler.level=ALL +java.util.logging.SimpleFormatter.format=%4$s: %5$s%6$s%n + +.level=INFO diff --git a/config/metadata/docs/src/test/java/io/helidon/config/metadata/docs/ConfigDocumentationTest.java b/config/metadata/docs/src/test/java/io/helidon/config/metadata/docs/ConfigDocumentationTest.java new file mode 100644 index 00000000000..9eb7402bb83 --- /dev/null +++ b/config/metadata/docs/src/test/java/io/helidon/config/metadata/docs/ConfigDocumentationTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2024 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.config.metadata.docs; + +import org.junit.jupiter.api.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +class ConfigDocumentationTest { + @Test + void testTitleFromFileName() { + String original = "io_helidon_tracing_jaeger_JaegerTracerBuilder.adoc"; + String expected = "JaegerTracerBuilder (tracing.jaeger)"; + String actual = ConfigDocs.titleFromFileName(original); + assertThat(actual, is(expected)); + } + @Test + void testHtmlParagraph() { + String original = """ + First +

      some text +

      some text

      some text + Some other text + """; + String expected = """ + First + some text + some text + some text + Some other text + """; + String actual = ConfigDocs.translateHtml(original); + assertThat(actual, is(expected)); + } + + @Test + void testHtmlUl() { + String original = """ + First ul:

      • text
      • text
      + Second ul: +
        +
      • text
      • +
      • text
      • +
      + """; + String expected = """ + First ul: + + - text + - text + + Second ul: + + - text + - text + + """; + String actual = ConfigDocs.translateHtml(original); + assertThat(actual, is(expected)); + } + + @Test + void testAtValue() { + String original = """ + Some value: {@value #DEFAULT_BASE_SCOPE} + Some value: {@value SomeType#SOME_CONSTANT} + """; + String expected = """ + Some value: `DEFAULT_BASE_SCOPE` + Some value: `SomeType#SOME_CONSTANT` + """; + String actual = ConfigDocs.translateHtml(original); + assertThat(actual, is(expected)); + } +} \ No newline at end of file diff --git a/config/metadata/metadata/pom.xml b/config/metadata/metadata/pom.xml new file mode 100644 index 00000000000..da5bb24158b --- /dev/null +++ b/config/metadata/metadata/pom.xml @@ -0,0 +1,53 @@ + + + + + 4.0.0 + + io.helidon.config + helidon-config-metadata-project + 4.1.0-SNAPSHOT + ../pom.xml + + helidon-config-metadata + Helidon Config Metadata + + + true + + + + Configuration Metadata annotations and processing. + + + + + org.junit.jupiter + junit-jupiter-api + test + + + org.hamcrest + hamcrest-all + test + + + diff --git a/config/metadata/src/main/java/io/helidon/config/metadata/Configured.java b/config/metadata/metadata/src/main/java/io/helidon/config/metadata/Configured.java similarity index 98% rename from config/metadata/src/main/java/io/helidon/config/metadata/Configured.java rename to config/metadata/metadata/src/main/java/io/helidon/config/metadata/Configured.java index 2825f15384a..f450c37051c 100644 --- a/config/metadata/src/main/java/io/helidon/config/metadata/Configured.java +++ b/config/metadata/metadata/src/main/java/io/helidon/config/metadata/Configured.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. + * Copyright (c) 2021, 2024 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. diff --git a/config/metadata/src/main/java/io/helidon/config/metadata/ConfiguredOption.java b/config/metadata/metadata/src/main/java/io/helidon/config/metadata/ConfiguredOption.java similarity index 99% rename from config/metadata/src/main/java/io/helidon/config/metadata/ConfiguredOption.java rename to config/metadata/metadata/src/main/java/io/helidon/config/metadata/ConfiguredOption.java index 84f8fdab7b9..0d4cf6f4e48 100644 --- a/config/metadata/src/main/java/io/helidon/config/metadata/ConfiguredOption.java +++ b/config/metadata/metadata/src/main/java/io/helidon/config/metadata/ConfiguredOption.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. + * Copyright (c) 2021, 2024 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. diff --git a/config/metadata/src/main/java/io/helidon/config/metadata/ConfiguredOptions.java b/config/metadata/metadata/src/main/java/io/helidon/config/metadata/ConfiguredOptions.java similarity index 95% rename from config/metadata/src/main/java/io/helidon/config/metadata/ConfiguredOptions.java rename to config/metadata/metadata/src/main/java/io/helidon/config/metadata/ConfiguredOptions.java index 7f414169af6..a3848c248ae 100644 --- a/config/metadata/src/main/java/io/helidon/config/metadata/ConfiguredOptions.java +++ b/config/metadata/metadata/src/main/java/io/helidon/config/metadata/ConfiguredOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. + * Copyright (c) 2021, 2024 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. diff --git a/config/metadata/src/main/java/io/helidon/config/metadata/ConfiguredValue.java b/config/metadata/metadata/src/main/java/io/helidon/config/metadata/ConfiguredValue.java similarity index 94% rename from config/metadata/src/main/java/io/helidon/config/metadata/ConfiguredValue.java rename to config/metadata/metadata/src/main/java/io/helidon/config/metadata/ConfiguredValue.java index dedc7d5a4ad..51cf9a2dda1 100644 --- a/config/metadata/src/main/java/io/helidon/config/metadata/ConfiguredValue.java +++ b/config/metadata/metadata/src/main/java/io/helidon/config/metadata/ConfiguredValue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. + * Copyright (c) 2021, 2024 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. diff --git a/config/metadata/src/main/java/io/helidon/config/metadata/package-info.java b/config/metadata/metadata/src/main/java/io/helidon/config/metadata/package-info.java similarity index 92% rename from config/metadata/src/main/java/io/helidon/config/metadata/package-info.java rename to config/metadata/metadata/src/main/java/io/helidon/config/metadata/package-info.java index 1b389cdee69..d7d8a53691e 100644 --- a/config/metadata/src/main/java/io/helidon/config/metadata/package-info.java +++ b/config/metadata/metadata/src/main/java/io/helidon/config/metadata/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Oracle and/or its affiliates. + * Copyright (c) 2021, 2024 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. diff --git a/config/metadata/src/main/java/module-info.java b/config/metadata/metadata/src/main/java/module-info.java similarity index 92% rename from config/metadata/src/main/java/module-info.java rename to config/metadata/metadata/src/main/java/module-info.java index a319e2e7fbf..bf22d35c213 100644 --- a/config/metadata/src/main/java/module-info.java +++ b/config/metadata/metadata/src/main/java/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. + * Copyright (c) 2021, 2024 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. diff --git a/config/metadata/pom.xml b/config/metadata/pom.xml index 2c0a0eddc48..d8bbb01a731 100644 --- a/config/metadata/pom.xml +++ b/config/metadata/pom.xml @@ -25,28 +25,40 @@ io.helidon.config helidon-config-project 4.1.0-SNAPSHOT + ../pom.xml - helidon-config-metadata - Helidon Config Metadata + + helidon-config-metadata-project + Helidon Config Metadata Project + pom + + + Configuration Metadata annotations and codegen. + - true + true - - Configuration Metadata annotations and processing. - + + metadata + codegen + processor + docs + - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - + + + + org.apache.maven.plugins + maven-dependency-plugin + + + check-dependencies + verify + + + + + diff --git a/config/metadata-processor/pom.xml b/config/metadata/processor/pom.xml similarity index 89% rename from config/metadata-processor/pom.xml rename to config/metadata/processor/pom.xml index 66427109e6a..b8b71ba3518 100644 --- a/config/metadata-processor/pom.xml +++ b/config/metadata/processor/pom.xml @@ -23,8 +23,9 @@ 4.0.0 io.helidon.config - helidon-config-project + helidon-config-metadata-project 4.1.0-SNAPSHOT + ../pom.xml helidon-config-metadata-processor Helidon Config Metadata Annotation Processor @@ -42,6 +43,10 @@ io.helidon.common.processor helidon-common-processor + + io.helidon.metadata + helidon-metadata-hson + org.junit.jupiter junit-jupiter-api diff --git a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/BlueprintUtil.java b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/BlueprintUtil.java similarity index 99% rename from config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/BlueprintUtil.java rename to config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/BlueprintUtil.java index 001b8a4d05d..0f3e73d7f9c 100644 --- a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/BlueprintUtil.java +++ b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/BlueprintUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2024 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. diff --git a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/ConfigMetadataHandler.java b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/ConfigMetadataHandler.java similarity index 94% rename from config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/ConfigMetadataHandler.java rename to config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/ConfigMetadataHandler.java index add14128c89..bfa8f1fce1d 100644 --- a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/ConfigMetadataHandler.java +++ b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/ConfigMetadataHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. + * Copyright (c) 2021, 2024 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. @@ -40,6 +40,7 @@ import io.helidon.common.processor.TypeInfoFactory; import io.helidon.common.types.TypeInfo; import io.helidon.common.types.TypeName; +import io.helidon.metadata.hson.Hson; import static io.helidon.config.metadata.processor.UsedTypes.BLUEPRINT; import static io.helidon.config.metadata.processor.UsedTypes.CONFIGURED; @@ -186,19 +187,20 @@ private void storeMetadata() { This is to allow merging of files - such as when we would want to create on-the-fly JSON for a project with only its dependencies. */ - JArray moduleArray = new JArray(); + List moduleArray = new ArrayList<>(); for (var module : moduleTypes.entrySet()) { String moduleName = module.getKey(); var types = module.getValue(); - JArray typeArray = new JArray(); + List typeArray = new ArrayList<>(); types.forEach(it -> newOptions.get(it).write(typeArray)); - moduleArray.add(new JObject() - .add("module", moduleName) - .add("types", typeArray)); + moduleArray.add(Hson.Object.builder() + .set("module", moduleName) + .setObjects("types", typeArray) + .build()); } - moduleArray.write(metaWriter); + Hson.Array.create(moduleArray).write(metaWriter); } catch (IOException e) { messager.printMessage(Diagnostic.Kind.ERROR, "Failed to write configuration metadata: " + e.getMessage()); e.printStackTrace(); diff --git a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/ConfigMetadataProcessor.java b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/ConfigMetadataProcessor.java similarity index 84% rename from config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/ConfigMetadataProcessor.java rename to config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/ConfigMetadataProcessor.java index 4c7a8e70400..f2a39e8f614 100644 --- a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/ConfigMetadataProcessor.java +++ b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/ConfigMetadataProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. + * Copyright (c) 2021, 2024 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. @@ -31,7 +31,10 @@ /** * Annotation processor. + * + * @deprecated use {@code helidon-config-metadata-codegen} instead */ +@Deprecated(forRemoval = true, since = "4.1.0") public class ConfigMetadataProcessor extends AbstractProcessor { private ConfigMetadataHandler handler; @@ -60,6 +63,10 @@ public synchronized void init(ProcessingEnvironment processingEnv) { handler = new ConfigMetadataHandler(); handler.init(processingEnv); + + processingEnv.getMessager() + .printWarning("Module helidon-config-metadata-processor is deprecated, " + + "please use io.helidon.config.metadata:helidon-config-metadata-codegen"); } @Override diff --git a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/ConfiguredAnnotation.java b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/ConfiguredAnnotation.java similarity index 98% rename from config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/ConfiguredAnnotation.java rename to config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/ConfiguredAnnotation.java index 8c41f8dc0a3..c5445064374 100644 --- a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/ConfiguredAnnotation.java +++ b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/ConfiguredAnnotation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2024 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. diff --git a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/ConfiguredOptionData.java b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/ConfiguredOptionData.java similarity index 99% rename from config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/ConfiguredOptionData.java rename to config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/ConfiguredOptionData.java index e1320526d23..656a8ac134b 100644 --- a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/ConfiguredOptionData.java +++ b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/ConfiguredOptionData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2024 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. diff --git a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/ConfiguredType.java b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/ConfiguredType.java similarity index 80% rename from config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/ConfiguredType.java rename to config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/ConfiguredType.java index 6b20030615b..6f37eae5edc 100644 --- a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/ConfiguredType.java +++ b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/ConfiguredType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. + * Copyright (c) 2021, 2024 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. @@ -16,6 +16,7 @@ package io.helidon.config.metadata.processor; +import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedList; import java.util.List; @@ -24,6 +25,7 @@ import java.util.stream.Collectors; import io.helidon.common.types.TypeName; +import io.helidon.metadata.hson.Hson; final class ConfiguredType { private final Set allProperties = new HashSet<>(); @@ -79,40 +81,40 @@ String prefix() { return configured.prefix().orElse(null); } - void write(JArray typeArray) { - JObject typeObject = new JObject(); + void write(List typeArray) { + var typeObject = Hson.Object.builder(); - typeObject.add("type", targetClass()); - typeObject.add("annotatedType", annotatedClass()); + typeObject.set("type", targetClass()); + typeObject.set("annotatedType", annotatedClass()); if (standalone()) { - typeObject.add("standalone", true); + typeObject.set("standalone", true); } - configured.prefix().ifPresent(it -> typeObject.add("prefix", it)); - configured.description().ifPresent(it -> typeObject.add("description", it)); + configured.prefix().ifPresent(it -> typeObject.set("prefix", it)); + configured.description().ifPresent(it -> typeObject.set("description", it)); if (!inherited.isEmpty()) { - typeObject.add("inherits", inherited.stream() + typeObject.setStrings("inherits", inherited.stream() .map(TypeName::fqName) .toList()); } if (!configured.provides().isEmpty()) { - typeObject.add("provides", configured.provides()); + typeObject.setStrings("provides", configured.provides()); } if (!producerMethods.isEmpty()) { - typeObject.add("producers", producerMethods.stream() + typeObject.setStrings("producers", producerMethods.stream() .map(Object::toString) .collect(Collectors.toList())); } - JArray options = new JArray(); + List options = new ArrayList<>(); for (ConfiguredProperty property : allProperties) { writeProperty(options, "", property); } - typeObject.add("options", options); + typeObject.setObjects("options", options); - typeArray.add(typeObject); + typeArray.add(typeObject.build()); } @Override @@ -130,43 +132,43 @@ private static String paramsToString(List params) { .collect(Collectors.joining(", ")); } - private void writeProperty(JArray optionsBuilder, + private void writeProperty(List optionsBuilder, String prefix, ConfiguredProperty property) { - JObject optionBuilder = new JObject(); + var optionBuilder = Hson.Object.builder(); if (property.key() != null && !property.key.isBlank()) { - optionBuilder.add("key", prefix(prefix, property.key())); + optionBuilder.set("key", prefix(prefix, property.key())); } if (!"java.lang.String".equals(property.type)) { - optionBuilder.add("type", property.type()); + optionBuilder.set("type", property.type()); } - optionBuilder.add("description", property.description()); + optionBuilder.set("description", property.description()); if (property.defaultValue() != null) { - optionBuilder.add("defaultValue", property.defaultValue()); + optionBuilder.set("defaultValue", property.defaultValue()); } if (property.experimental) { - optionBuilder.add("experimental", true); + optionBuilder.set("experimental", true); } if (!property.optional) { - optionBuilder.add("required", true); + optionBuilder.set("required", true); } if (!property.kind().equals("VALUE")) { - optionBuilder.add("kind", property.kind()); + optionBuilder.set("kind", property.kind()); } if (property.provider) { - optionBuilder.add("provider", true); - optionBuilder.add("providerType", property.providerType.fqName()); + optionBuilder.set("provider", true); + optionBuilder.set("providerType", property.providerType.fqName()); } if (property.deprecated()) { - optionBuilder.add("deprecated", true); + optionBuilder.set("deprecated", true); } if (property.merge()) { - optionBuilder.add("merge", true); + optionBuilder.set("merge", true); } String method = property.builderMethod(); if (method != null) { - optionBuilder.add("method", method); + optionBuilder.set("method", method); } if (property.configuredType != null) { String finalPrefix; @@ -179,18 +181,19 @@ private void writeProperty(JArray optionsBuilder, .forEach(it -> writeProperty(optionsBuilder, finalPrefix, it)); } if (!property.allowedValues.isEmpty()) { - JArray allowedValues = new JArray(); + List allowedValues = new ArrayList<>(); for (ConfiguredOptionData.AllowedValue allowedValue : property.allowedValues) { - allowedValues.add(new JObject() - .add("value", allowedValue.value()) - .add("description", allowedValue.description())); + allowedValues.add(Hson.Object.builder() + .set("value", allowedValue.value()) + .set("description", allowedValue.description()) + .build()); } - optionBuilder.add("allowedValues", allowedValues); + optionBuilder.setObjects("allowedValues", allowedValues); } - optionsBuilder.add(optionBuilder); + optionsBuilder.add(optionBuilder.build()); } private String prefix(String currentPrefix, String newSuffix) { diff --git a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/Javadoc.java b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/Javadoc.java similarity index 95% rename from config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/Javadoc.java rename to config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/Javadoc.java index a8c19c5b4ae..1dac7287f2e 100644 --- a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/Javadoc.java +++ b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/Javadoc.java @@ -18,8 +18,6 @@ import java.util.regex.Pattern; -import static io.helidon.common.processor.GeneratorTools.capitalize; - /* Possible improvements: - @link - create a proper javadoc reference (i.e. always fully qualified reference), such as: @@ -27,6 +25,7 @@ - @value - if possible, find the actual value (string, int etc.) and add it as `thevalue` - @see - create a proper javadoc reference (as for @link) */ +@Deprecated(forRemoval = true) final class Javadoc { private static final Pattern JAVADOC_CODE = Pattern.compile("\\{@code (.*?)}"); private static final Pattern JAVADOC_LINK = Pattern.compile("\\{@link (.*?)}"); @@ -55,6 +54,7 @@ private Javadoc() { * @param docComment "raw" javadoc from the source code * @return description of the option */ + @SuppressWarnings("removal") static String parse(String docComment) { if (docComment == null) { return ""; @@ -78,7 +78,8 @@ static String parse(String docComment) { index = javadoc.indexOf("@return"); if (index > -1) { - javadoc = javadoc.substring(0, index) + capitalize(javadoc.substring(index + 8)); + javadoc = javadoc.substring(0, index) + + io.helidon.common.processor.GeneratorTools.capitalize(javadoc.substring(index + 8)); } return javadoc.trim(); diff --git a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/TypeHandler.java b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/TypeHandler.java similarity index 92% rename from config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/TypeHandler.java rename to config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/TypeHandler.java index 87cc0f8fbbf..bcc448dc490 100644 --- a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/TypeHandler.java +++ b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/TypeHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2024 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. diff --git a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerBase.java b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerBase.java similarity index 100% rename from config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerBase.java rename to config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerBase.java diff --git a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerBuilderApi.java b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerBuilderApi.java similarity index 100% rename from config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerBuilderApi.java rename to config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerBuilderApi.java diff --git a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerMetaApi.java b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerMetaApi.java similarity index 99% rename from config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerMetaApi.java rename to config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerMetaApi.java index 3da5d9db87f..80b887ab7ef 100644 --- a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerMetaApi.java +++ b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerMetaApi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2024 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. diff --git a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerMetaApiBase.java b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerMetaApiBase.java similarity index 98% rename from config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerMetaApiBase.java rename to config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerMetaApiBase.java index 9f32e4a7e1f..4bfc38776a0 100644 --- a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerMetaApiBase.java +++ b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerMetaApiBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2024 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. diff --git a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerMetaApiBlueprint.java b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerMetaApiBlueprint.java similarity index 98% rename from config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerMetaApiBlueprint.java rename to config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerMetaApiBlueprint.java index bd3dbf03e4a..55be809ec67 100644 --- a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerMetaApiBlueprint.java +++ b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerMetaApiBlueprint.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2024 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. diff --git a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerResult.java b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerResult.java similarity index 94% rename from config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerResult.java rename to config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerResult.java index 213d81b8632..0aa051d07cb 100644 --- a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerResult.java +++ b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/TypeHandlerResult.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2024 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. diff --git a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/UsedTypes.java b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/UsedTypes.java similarity index 95% rename from config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/UsedTypes.java rename to config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/UsedTypes.java index 62e11c460c7..64f2dd203c9 100644 --- a/config/metadata-processor/src/main/java/io/helidon/config/metadata/processor/UsedTypes.java +++ b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/UsedTypes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2024 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. @@ -30,7 +30,6 @@ final class UsedTypes { /* Using builder API */ - static final TypeName BUILDER = TypeName.create("io.helidon.common.Builder"); static final TypeName COMMON_CONFIG = TypeName.create("io.helidon.common.config.Config"); static final TypeName CONFIG = TypeName.create("io.helidon.config.Config"); static final TypeName PROTOTYPE_FACTORY = TypeName.create("io.helidon.builder.api.Prototype.Factory"); diff --git a/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/package-info.java b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/package-info.java new file mode 100644 index 00000000000..0aeef222c5d --- /dev/null +++ b/config/metadata/processor/src/main/java/io/helidon/config/metadata/processor/package-info.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2021, 2024 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. + */ + +/** + * Annotation processor generating JSON metadata for configuration. + *

      + * This module is deprecated, use {@code helidon-config-metadata-codegen} together with {@code helidon-codegen-apt}. + */ +@Deprecated(forRemoval = true, since = "4.1.0") +package io.helidon.config.metadata.processor; diff --git a/config/metadata-processor/src/main/java/module-info.java b/config/metadata/processor/src/main/java/module-info.java similarity index 79% rename from config/metadata-processor/src/main/java/module-info.java rename to config/metadata/processor/src/main/java/module-info.java index e12f1089df0..40d4b25473e 100644 --- a/config/metadata-processor/src/main/java/module-info.java +++ b/config/metadata/processor/src/main/java/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. + * Copyright (c) 2021, 2024 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. @@ -16,11 +16,15 @@ /** * Annotation processor generating JSON metadata for configuration. + * + * @deprecated use {@code helidon-config-metadata-codegen} together with {@code helidon-codegen-apt} */ +@Deprecated(forRemoval = true, since = "4.1.0") module io.helidon.config.metadata.processor { requires java.compiler; requires io.helidon.common.types; + requires io.helidon.metadata.hson; requires io.helidon.common.processor; exports io.helidon.config.metadata.processor; diff --git a/config/metadata-processor/src/test/java/io/helidon/config/metadata/processor/ConfigMetadataHandlerTest.java b/config/metadata/processor/src/test/java/io/helidon/config/metadata/processor/ConfigMetadataHandlerTest.java similarity index 95% rename from config/metadata-processor/src/test/java/io/helidon/config/metadata/processor/ConfigMetadataHandlerTest.java rename to config/metadata/processor/src/test/java/io/helidon/config/metadata/processor/ConfigMetadataHandlerTest.java index 42f0d3dee08..16fd212fb3a 100644 --- a/config/metadata-processor/src/test/java/io/helidon/config/metadata/processor/ConfigMetadataHandlerTest.java +++ b/config/metadata/processor/src/test/java/io/helidon/config/metadata/processor/ConfigMetadataHandlerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. + * Copyright (c) 2021, 2024 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. diff --git a/config/pom.xml b/config/pom.xml index eda2325f10b..d923bc1f73c 100644 --- a/config/pom.xml +++ b/config/pom.xml @@ -48,7 +48,6 @@ config-mp yaml-mp metadata - metadata-processor hocon-mp diff --git a/config/tests/config-metadata-builder-api/pom.xml b/config/tests/config-metadata-builder-api/pom.xml index ca53c2bbb61..00392d57400 100644 --- a/config/tests/config-metadata-builder-api/pom.xml +++ b/config/tests/config-metadata-builder-api/pom.xml @@ -73,8 +73,8 @@ - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} @@ -91,8 +91,8 @@ - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} diff --git a/config/tests/config-metadata-meta-api/pom.xml b/config/tests/config-metadata-meta-api/pom.xml index fd21d2d01b9..9db844f3b69 100644 --- a/config/tests/config-metadata-meta-api/pom.xml +++ b/config/tests/config-metadata-meta-api/pom.xml @@ -70,16 +70,26 @@ - io.helidon.config - helidon-config-metadata-processor + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} diff --git a/cors/pom.xml b/cors/pom.xml index 8de7b3cd3dd..c087d80befe 100644 --- a/cors/pom.xml +++ b/cors/pom.xml @@ -77,16 +77,26 @@ - io.helidon.config - helidon-config-metadata-processor + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} diff --git a/dbclient/hikari/pom.xml b/dbclient/hikari/pom.xml index ab226cf4bbe..1e0b62fc3b5 100644 --- a/dbclient/hikari/pom.xml +++ b/dbclient/hikari/pom.xml @@ -91,8 +91,8 @@ ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} @@ -114,8 +114,8 @@ - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} diff --git a/dbclient/hikari/src/main/java/module-info.java b/dbclient/hikari/src/main/java/module-info.java index 60ee7341a70..45c7f739e77 100644 --- a/dbclient/hikari/src/main/java/module-info.java +++ b/dbclient/hikari/src/main/java/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2024 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. @@ -37,7 +37,8 @@ requires transitive io.helidon.dbclient; requires transitive io.helidon.dbclient.jdbc; requires transitive io.helidon.builder.api; - requires transitive io.helidon.config.metadata; + + requires static io.helidon.config.metadata; exports io.helidon.dbclient.hikari; exports io.helidon.dbclient.hikari.spi; diff --git a/dbclient/jdbc/pom.xml b/dbclient/jdbc/pom.xml index 0ba4f67975a..d963308a716 100644 --- a/dbclient/jdbc/pom.xml +++ b/dbclient/jdbc/pom.xml @@ -49,6 +49,7 @@ io.helidon.config helidon-config-metadata + true io.helidon.config @@ -90,8 +91,8 @@ ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} @@ -114,8 +115,8 @@ - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} diff --git a/dbclient/jdbc/src/main/java/module-info.java b/dbclient/jdbc/src/main/java/module-info.java index 5a70ccddcd0..c8a3dfcd4a0 100644 --- a/dbclient/jdbc/src/main/java/module-info.java +++ b/dbclient/jdbc/src/main/java/module-info.java @@ -34,9 +34,10 @@ requires transitive io.helidon.builder.api; requires transitive io.helidon.common; - requires transitive io.helidon.config.metadata; requires transitive io.helidon.dbclient; + requires static io.helidon.config.metadata; + exports io.helidon.dbclient.jdbc; exports io.helidon.dbclient.jdbc.spi; diff --git a/docs/README.md b/docs/README.md index f4cefdd5ca5..cafd35088f4 100644 --- a/docs/README.md +++ b/docs/README.md @@ -19,6 +19,11 @@ Build just the javadocs: mvn package -Pjavadoc -Dhelidon.sitegen.skip=true ``` +Build docs and also update config reference docs: +```bash +mvn package -Pconfigdoc +``` + ## Serve ```bash diff --git a/docs/pom.xml b/docs/pom.xml index 50387533dc3..322a0f11009 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -43,6 +43,10 @@ pom true + + io.helidon.config.metadata + helidon-config-metadata-docs + org.mockito mockito-core @@ -125,6 +129,34 @@ + + configdoc + + + + org.codehaus.mojo + exec-maven-plugin + + + regenerate-config-docs + + java + + generate-sources + + + + ${project.basedir}/src/main/asciidoc/config + io.helidon.config.metadata.docs.Main + + helidon-logging-slf4j-${helidon.version}.jar + helidon-logging-log4j-${helidon.version}.jar + + + + + + javadoc @@ -167,6 +199,7 @@ *:*-tests + io.helidon.config.metadata:helidon-config-metadata-docs **/src/main/templates diff --git a/docs/src/main/asciidoc/config/config_reference.adoc b/docs/src/main/asciidoc/config/config_reference.adoc index c94f4570f9d..a0a05104fc4 100644 --- a/docs/src/main/asciidoc/config/config_reference.adoc +++ b/docs/src/main/asciidoc/config/config_reference.adoc @@ -30,16 +30,16 @@ The following section lists all configurable types in Helidon. - xref:{rootdir}/config/io_helidon_common_configurable_AllowList.adoc[AllowList (common.configurable)] - xref:{rootdir}/config/io_helidon_faulttolerance_Async.adoc[Async (faulttolerance)] - xref:{rootdir}/config/io_helidon_security_providers_oidc_common_BaseBuilder.adoc[BaseBuilder (security.providers.oidc.common)] -- xref:{rootdir}/config/io_helidon_metrics_api_ComponentMetricsSettings_Builder.adoc[Builder (metrics.api.ComponentMetricsSettings)] - xref:{rootdir}/config/io_helidon_security_providers_idcs_mapper_IdcsRoleMapperProviderBase_Builder.adoc[Builder (security.providers.idcs.mapper.IdcsRoleMapperProviderBase)] - xref:{rootdir}/config/io_helidon_webserver_servicecommon_HelidonFeatureSupport_Builder.adoc[Builder (webserver.servicecommon.HelidonFeatureSupport)] -- xref:{rootdir}/config/io_helidon_webserver_servicecommon_RestServiceSettings_Builder.adoc[Builder (webserver.servicecommon.RestServiceSettings)] - xref:{rootdir}/config/io_helidon_faulttolerance_Bulkhead.adoc[Bulkhead (faulttolerance)] - xref:{rootdir}/config/io_helidon_faulttolerance_CircuitBreaker.adoc[CircuitBreaker (faulttolerance)] +- xref:{rootdir}/config/io_helidon_metrics_api_ComponentMetricsSettings.adoc[ComponentMetricsSettings (metrics.api)] - xref:{rootdir}/config/io_helidon_integrations_oci_ConfigFileMethodConfig.adoc[ConfigFileMethodConfig (integrations.oci)] - xref:{rootdir}/config/io_helidon_integrations_oci_ConfigMethodConfig.adoc[ConfigMethodConfig (integrations.oci)] - xref:{rootdir}/config/io_helidon_webserver_observe_config_ConfigObserver.adoc[ConfigObserver (webserver.observe.config)] - xref:{rootdir}/config/io_helidon_security_providers_httpauth_ConfigUserStore_ConfigUser.adoc[ConfigUser (security.providers.httpauth.ConfigUserStore)] +- xref:{rootdir}/config/io_helidon_security_providers_config_vault_ConfigVaultProvider.adoc[ConfigVaultProvider (security.providers.config.vault)] - xref:{rootdir}/config/io_helidon_webserver_ConnectionConfig.adoc[ConnectionConfig (webserver)] - xref:{rootdir}/config/io_helidon_http_encoding_ContentEncodingContext.adoc[ContentEncodingContext (http.encoding)] - xref:{rootdir}/config/io_helidon_webserver_context_ContextFeature.adoc[ContextFeature (webserver.context)] @@ -53,6 +53,7 @@ The following section lists all configurable types in Helidon. - xref:{rootdir}/config/io_helidon_webclient_grpc_GrpcClient.adoc[GrpcClient (webclient.grpc)] - xref:{rootdir}/config/io_helidon_webclient_grpc_GrpcClientProtocolConfig.adoc[GrpcClientProtocolConfig (webclient.grpc)] - xref:{rootdir}/config/io_helidon_webserver_grpc_GrpcConfig.adoc[GrpcConfig (webserver.grpc)] +- xref:{rootdir}/config/io_helidon_webserver_grpc_GrpcTracingConfig.adoc[GrpcTracingConfig (webserver.grpc)] - xref:{rootdir}/config/io_helidon_security_providers_header_HeaderAtnProvider.adoc[HeaderAtnProvider (security.providers.header)] - xref:{rootdir}/config/io_helidon_security_providers_httpsign_SignedHeadersConfig_HeadersConfig.adoc[HeadersConfig (security.providers.httpsign.SignedHeadersConfig)] - xref:{rootdir}/config/io_helidon_webserver_observe_health_HealthObserver.adoc[HealthObserver (webserver.observe.health)] @@ -67,10 +68,12 @@ The following section lists all configurable types in Helidon. - xref:{rootdir}/config/io_helidon_security_providers_httpsign_HttpSignProvider.adoc[HttpSignProvider (security.providers.httpsign)] - xref:{rootdir}/config/io_helidon_security_providers_idcs_mapper_IdcsMtRoleMapperProvider.adoc[IdcsMtRoleMapperProvider (security.providers.idcs.mapper)] - xref:{rootdir}/config/io_helidon_security_providers_idcs_mapper_IdcsRoleMapperProvider.adoc[IdcsRoleMapperProvider (security.providers.idcs.mapper)] +- xref:{rootdir}/config/io_helidon_integrations_oci_ImdsInstanceInfo.adoc[ImdsInstanceInfo (integrations.oci)] - xref:{rootdir}/config/io_helidon_security_providers_httpsign_InboundClientDefinition.adoc[InboundClientDefinition (security.providers.httpsign)] - xref:{rootdir}/config/io_helidon_webserver_observe_info_InfoObserver.adoc[InfoObserver (webserver.observe.info)] - xref:{rootdir}/config/io_helidon_tracing_providers_jaeger_JaegerTracerBuilder.adoc[JaegerTracerBuilder (tracing.providers.jaeger)] - xref:{rootdir}/config/io_helidon_dbclient_jdbc_JdbcParametersConfig.adoc[JdbcParametersConfig (dbclient.jdbc)] +- xref:{rootdir}/config/io_helidon_microprofile_jwt_auth_JwtAuthProvider.adoc[JwtAuthProvider (microprofile.jwt.auth)] - xref:{rootdir}/config/io_helidon_security_providers_jwt_JwtProvider.adoc[JwtProvider (security.providers.jwt)] - xref:{rootdir}/config/io_helidon_metrics_api_KeyPerformanceIndicatorMetricsConfig.adoc[KeyPerformanceIndicatorMetricsConfig (metrics.api)] - xref:{rootdir}/config/io_helidon_common_pki_Keys.adoc[Keys (common.pki)] @@ -104,12 +107,14 @@ The following section lists all configurable types in Helidon. - xref:{rootdir}/config/io_helidon_webclient_api_Proxy.adoc[Proxy (webclient.api)] - xref:{rootdir}/config/io_helidon_http_RequestedUriDiscoveryContext.adoc[RequestedUriDiscoveryContext (http)] - xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource (common.configurable)] +- xref:{rootdir}/config/io_helidon_webserver_servicecommon_RestServiceSettings.adoc[RestServiceSettings (webserver.servicecommon)] - xref:{rootdir}/config/io_helidon_faulttolerance_Retry.adoc[Retry (faulttolerance)] - xref:{rootdir}/config/io_helidon_common_tls_RevocationConfig.adoc[RevocationConfig (common.tls)] - xref:{rootdir}/config/io_helidon_common_configurable_ScheduledThreadPoolConfig.adoc[ScheduledThreadPoolConfig (common.configurable)] - xref:{rootdir}/config/io_helidon_common_configurable_ScheduledThreadPoolSupplier.adoc[ScheduledThreadPoolSupplier (common.configurable)] - xref:{rootdir}/config/io_helidon_metrics_api_ScopeConfig.adoc[ScopeConfig (metrics.api)] - xref:{rootdir}/config/io_helidon_metrics_api_ScopingConfig.adoc[ScopingConfig (metrics.api)] +- xref:{rootdir}/config/io_helidon_security_providers_config_vault_ConfigVaultProvider_SecretConfig.adoc[SecretConfig (security.providers.config.vault.ConfigVaultProvider)] - xref:{rootdir}/config/io_helidon_security_Security.adoc[Security (security)] - xref:{rootdir}/config/io_helidon_webserver_security_SecurityFeature.adoc[SecurityFeature (webserver.security)] - xref:{rootdir}/config/io_helidon_webserver_security_SecurityHandler.adoc[SecurityHandler (webserver.security)] diff --git a/docs/src/main/asciidoc/config/io_helidon_common_configurable_AllowList.adoc b/docs/src/main/asciidoc/config/io_helidon_common_configurable_AllowList.adoc index 733341db9e0..44d46254466 100644 --- a/docs/src/main/asciidoc/config/io_helidon_common_configurable_AllowList.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_common_configurable_AllowList.adoc @@ -43,34 +43,34 @@ Type: link:{javadoc-base-url}/io.helidon.common.configurable/io/helidon/common/c |key |type |default value |description |`allow.all` |boolean |`false` |Allows all strings to match (subject to "deny" conditions). An `allow.all` setting of `false` does - not deny all strings but rather represents the absence of a universal match, meaning that other allow and deny settings - determine the matching outcomes. +not deny all strings but rather represents the absence of a universal match, meaning that other allow and deny settings +determine the matching outcomes. - Whether to allow all strings to match (subject to "deny" conditions) +Whether to allow all strings to match (subject to "deny" conditions) |`allow.exact` |string[] |{nbsp} |Exact strings to allow. - Exact strings to allow +Exact strings to allow |`allow.pattern` |Pattern[] |{nbsp} |Patterns specifying strings to allow. - Patterns which allow matching +Patterns which allow matching |`allow.prefix` |string[] |{nbsp} |Prefixes specifying strings to allow. - Prefixes which allow matching +Prefixes which allow matching |`allow.suffix` |string[] |{nbsp} |Suffixes specifying strings to allow. - Suffixes which allow matching +Suffixes which allow matching |`deny.exact` |string[] |{nbsp} |Exact strings to deny. - Exact strings to allow +Exact strings to deny |`deny.pattern` |Pattern[] |{nbsp} |Patterns specifying strings to deny. - Patterns which deny matching +Patterns which deny matching |`deny.prefix` |string[] |{nbsp} |Prefixes specifying strings to deny. - Prefixes which deny matching +Prefixes which deny matching |`deny.suffix` |string[] |{nbsp} |Suffixes specifying strings to deny. - Suffixes which deny matching +Suffixes which deny matching |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_common_configurable_LruCache.adoc b/docs/src/main/asciidoc/config/io_helidon_common_configurable_LruCache.adoc index c06372ef3cc..b840fef899d 100644 --- a/docs/src/main/asciidoc/config/io_helidon_common_configurable_LruCache.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_common_configurable_LruCache.adoc @@ -44,7 +44,7 @@ Type: link:{javadoc-base-url}/io.helidon.common.configurable/io/helidon/common/c |`capacity` |int |`10000` |Configure capacity of the cache. Defaults to LruCache.DEFAULT_CAPACITY. - Maximal number of records in the cache before the oldest one is removed +Maximal number of records in the cache before the oldest one is removed |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_common_configurable_Resource.adoc b/docs/src/main/asciidoc/config/io_helidon_common_configurable_Resource.adoc index c28b25ee425..971519477d9 100644 --- a/docs/src/main/asciidoc/config/io_helidon_common_configurable_Resource.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_common_configurable_Resource.adoc @@ -44,34 +44,34 @@ Type: link:{javadoc-base-url}/io.helidon.common.configurable/io/helidon/common/c |`content` |string |{nbsp} |Binary content of the resource (base64 encoded). - Binary content +Binary content |`content-plain` |string |{nbsp} |Plain content of the resource (text). - Plain content +Plain content |`description` |string |{nbsp} |Description of this resource when configured through plain text or binary. - Description +Description |`path` |Path |{nbsp} |Resource is located on filesystem. - Path of the resource +Path of the resource |`proxy-host` |string |{nbsp} |Host of the proxy when using URI. - Proxy host +Proxy host |`proxy-port` |int |`80` |Port of the proxy when using URI. - Proxy port +Proxy port |`resource-path` |string |{nbsp} |Resource is located on classpath. - Classpath location of the resource +Classpath location of the resource |`uri` |URI |{nbsp} |Resource is available on a java.net.URI. - Of the resource - See proxy() - See useProxy() +Of the resource +See proxy() +See useProxy() |`use-proxy` |boolean |`true` |Whether to use proxy. If set to `false`, proxy will not be used even if configured. - When set to `true` (default), proxy will be used if configured. +When set to `true` (default), proxy will be used if configured. - Whether to use proxy if configured +Whether to use proxy if configured |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_common_configurable_ScheduledThreadPoolConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_common_configurable_ScheduledThreadPoolConfig.adoc index 8e8a4a02a3d..4343535007a 100644 --- a/docs/src/main/asciidoc/config/io_helidon_common_configurable_ScheduledThreadPoolConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_common_configurable_ScheduledThreadPoolConfig.adoc @@ -43,26 +43,26 @@ Type: link:{javadoc-base-url}/io.helidon.common.configurable/io/helidon/common/c |key |type |default value |description |`core-pool-size` |int |`16` |Core pool size of the thread pool executor. - Defaults to DEFAULT_CORE_POOL_SIZE. +Defaults to DEFAULT_CORE_POOL_SIZE. - CorePoolSize see java.util.concurrent.ThreadPoolExecutor.getCorePoolSize() +CorePoolSize see java.util.concurrent.ThreadPoolExecutor.getCorePoolSize() |`is-daemon` |boolean |`true` |Is daemon of the thread pool executor. - Defaults to DEFAULT_IS_DAEMON. +Defaults to DEFAULT_IS_DAEMON. - Whether the threads are daemon threads +Whether the threads are daemon threads |`prestart` |boolean |`false` |Whether to prestart core threads in this thread pool executor. - Defaults to DEFAULT_PRESTART. +Defaults to DEFAULT_PRESTART. - Whether to prestart the threads +Whether to prestart the threads |`thread-name-prefix` |string |`helidon-` |Name prefix for threads in this thread pool executor. - Defaults to DEFAULT_THREAD_NAME_PREFIX. +Defaults to DEFAULT_THREAD_NAME_PREFIX. - Prefix of a thread name +Prefix of a thread name |`virtual-threads` |boolean |{nbsp} |When configured to `true`, an unbounded virtual executor service (project Loom) will be used. - If enabled, all other configuration options of this executor service are ignored! +If enabled, all other configuration options of this executor service are ignored! - Whether to use virtual threads or not, defaults to `false` +Whether to use virtual threads or not, defaults to `false` |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_common_configurable_ScheduledThreadPoolSupplier.adoc b/docs/src/main/asciidoc/config/io_helidon_common_configurable_ScheduledThreadPoolSupplier.adoc index 8e8a4a02a3d..4343535007a 100644 --- a/docs/src/main/asciidoc/config/io_helidon_common_configurable_ScheduledThreadPoolSupplier.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_common_configurable_ScheduledThreadPoolSupplier.adoc @@ -43,26 +43,26 @@ Type: link:{javadoc-base-url}/io.helidon.common.configurable/io/helidon/common/c |key |type |default value |description |`core-pool-size` |int |`16` |Core pool size of the thread pool executor. - Defaults to DEFAULT_CORE_POOL_SIZE. +Defaults to DEFAULT_CORE_POOL_SIZE. - CorePoolSize see java.util.concurrent.ThreadPoolExecutor.getCorePoolSize() +CorePoolSize see java.util.concurrent.ThreadPoolExecutor.getCorePoolSize() |`is-daemon` |boolean |`true` |Is daemon of the thread pool executor. - Defaults to DEFAULT_IS_DAEMON. +Defaults to DEFAULT_IS_DAEMON. - Whether the threads are daemon threads +Whether the threads are daemon threads |`prestart` |boolean |`false` |Whether to prestart core threads in this thread pool executor. - Defaults to DEFAULT_PRESTART. +Defaults to DEFAULT_PRESTART. - Whether to prestart the threads +Whether to prestart the threads |`thread-name-prefix` |string |`helidon-` |Name prefix for threads in this thread pool executor. - Defaults to DEFAULT_THREAD_NAME_PREFIX. +Defaults to DEFAULT_THREAD_NAME_PREFIX. - Prefix of a thread name +Prefix of a thread name |`virtual-threads` |boolean |{nbsp} |When configured to `true`, an unbounded virtual executor service (project Loom) will be used. - If enabled, all other configuration options of this executor service are ignored! +If enabled, all other configuration options of this executor service are ignored! - Whether to use virtual threads or not, defaults to `false` +Whether to use virtual threads or not, defaults to `false` |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_common_configurable_ThreadPoolConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_common_configurable_ThreadPoolConfig.adoc index 0470d14e859..27843db096e 100644 --- a/docs/src/main/asciidoc/config/io_helidon_common_configurable_ThreadPoolConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_common_configurable_ThreadPoolConfig.adoc @@ -43,58 +43,58 @@ Type: link:{javadoc-base-url}/io.helidon.common.configurable/io/helidon/common/c |key |type |default value |description |`core-pool-size` |int |`10` |Core pool size of the thread pool executor. - Defaults to DEFAULT_CORE_POOL_SIZE. +Defaults to DEFAULT_CORE_POOL_SIZE. - CorePoolSize see java.util.concurrent.ThreadPoolExecutor.getCorePoolSize() +CorePoolSize see java.util.concurrent.ThreadPoolExecutor.getCorePoolSize() |`growth-rate` |int |`0` |The percentage of task submissions that should result in adding threads, expressed as a value from 1 to 100. The - rate applies only when all of the following are true: +rate applies only when all of the following are true: - the pool size is below the maximum, and - there are no idle threads, and - the number of tasks in the queue exceeds the `growthThreshold` For example, a rate of 20 means that while these conditions are met one thread will be added for every 5 submitted - tasks. +tasks. - Defaults to DEFAULT_GROWTH_RATE +Defaults to DEFAULT_GROWTH_RATE - The growth rate +The growth rate |`growth-threshold` |int |`1000` |The queue size above which pool growth will be considered if the pool is not fixed size. - Defaults to DEFAULT_GROWTH_THRESHOLD. +Defaults to DEFAULT_GROWTH_THRESHOLD. - The growth threshold +The growth threshold |`is-daemon` |boolean |`true` |Is daemon of the thread pool executor. - Defaults to DEFAULT_IS_DAEMON. +Defaults to DEFAULT_IS_DAEMON. - Whether the threads are daemon threads +Whether the threads are daemon threads |`keep-alive` |Duration |`PT3M` |Keep alive of the thread pool executor. - Defaults to DEFAULT_KEEP_ALIVE. +Defaults to DEFAULT_KEEP_ALIVE. - Keep alive see java.util.concurrent.ThreadPoolExecutor.getKeepAliveTime(java.util.concurrent.TimeUnit) +Keep alive see java.util.concurrent.ThreadPoolExecutor.getKeepAliveTime(java.util.concurrent.TimeUnit) |`max-pool-size` |int |`50` |Max pool size of the thread pool executor. - Defaults to DEFAULT_MAX_POOL_SIZE. +Defaults to DEFAULT_MAX_POOL_SIZE. - MaxPoolSize see java.util.concurrent.ThreadPoolExecutor.getMaximumPoolSize() +MaxPoolSize see java.util.concurrent.ThreadPoolExecutor.getMaximumPoolSize() |`name` |string |{nbsp} |Name of this thread pool executor. - The pool name +The pool name |`queue-capacity` |int |`10000` |Queue capacity of the thread pool executor. - Defaults to DEFAULT_QUEUE_CAPACITY. +Defaults to DEFAULT_QUEUE_CAPACITY. - Capacity of the queue backing the executor +Capacity of the queue backing the executor |`should-prestart` |boolean |`true` |Whether to prestart core threads in this thread pool executor. - Defaults to DEFAULT_PRESTART. +Defaults to DEFAULT_PRESTART. - Whether to prestart the threads +Whether to prestart the threads |`thread-name-prefix` |string |{nbsp} |Name prefix for threads in this thread pool executor. - Defaults to DEFAULT_THREAD_NAME_PREFIX. +Defaults to DEFAULT_THREAD_NAME_PREFIX. - Prefix of a thread name +Prefix of a thread name |`virtual-threads` |boolean |{nbsp} |When configured to `true`, an unbounded virtual executor service (project Loom) will be used. - If enabled, all other configuration options of this executor service are ignored! +If enabled, all other configuration options of this executor service are ignored! - Whether to use virtual threads or not, defaults to `false` +Whether to use virtual threads or not, defaults to `false` |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_common_configurable_ThreadPoolSupplier.adoc b/docs/src/main/asciidoc/config/io_helidon_common_configurable_ThreadPoolSupplier.adoc index 0470d14e859..27843db096e 100644 --- a/docs/src/main/asciidoc/config/io_helidon_common_configurable_ThreadPoolSupplier.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_common_configurable_ThreadPoolSupplier.adoc @@ -43,58 +43,58 @@ Type: link:{javadoc-base-url}/io.helidon.common.configurable/io/helidon/common/c |key |type |default value |description |`core-pool-size` |int |`10` |Core pool size of the thread pool executor. - Defaults to DEFAULT_CORE_POOL_SIZE. +Defaults to DEFAULT_CORE_POOL_SIZE. - CorePoolSize see java.util.concurrent.ThreadPoolExecutor.getCorePoolSize() +CorePoolSize see java.util.concurrent.ThreadPoolExecutor.getCorePoolSize() |`growth-rate` |int |`0` |The percentage of task submissions that should result in adding threads, expressed as a value from 1 to 100. The - rate applies only when all of the following are true: +rate applies only when all of the following are true: - the pool size is below the maximum, and - there are no idle threads, and - the number of tasks in the queue exceeds the `growthThreshold` For example, a rate of 20 means that while these conditions are met one thread will be added for every 5 submitted - tasks. +tasks. - Defaults to DEFAULT_GROWTH_RATE +Defaults to DEFAULT_GROWTH_RATE - The growth rate +The growth rate |`growth-threshold` |int |`1000` |The queue size above which pool growth will be considered if the pool is not fixed size. - Defaults to DEFAULT_GROWTH_THRESHOLD. +Defaults to DEFAULT_GROWTH_THRESHOLD. - The growth threshold +The growth threshold |`is-daemon` |boolean |`true` |Is daemon of the thread pool executor. - Defaults to DEFAULT_IS_DAEMON. +Defaults to DEFAULT_IS_DAEMON. - Whether the threads are daemon threads +Whether the threads are daemon threads |`keep-alive` |Duration |`PT3M` |Keep alive of the thread pool executor. - Defaults to DEFAULT_KEEP_ALIVE. +Defaults to DEFAULT_KEEP_ALIVE. - Keep alive see java.util.concurrent.ThreadPoolExecutor.getKeepAliveTime(java.util.concurrent.TimeUnit) +Keep alive see java.util.concurrent.ThreadPoolExecutor.getKeepAliveTime(java.util.concurrent.TimeUnit) |`max-pool-size` |int |`50` |Max pool size of the thread pool executor. - Defaults to DEFAULT_MAX_POOL_SIZE. +Defaults to DEFAULT_MAX_POOL_SIZE. - MaxPoolSize see java.util.concurrent.ThreadPoolExecutor.getMaximumPoolSize() +MaxPoolSize see java.util.concurrent.ThreadPoolExecutor.getMaximumPoolSize() |`name` |string |{nbsp} |Name of this thread pool executor. - The pool name +The pool name |`queue-capacity` |int |`10000` |Queue capacity of the thread pool executor. - Defaults to DEFAULT_QUEUE_CAPACITY. +Defaults to DEFAULT_QUEUE_CAPACITY. - Capacity of the queue backing the executor +Capacity of the queue backing the executor |`should-prestart` |boolean |`true` |Whether to prestart core threads in this thread pool executor. - Defaults to DEFAULT_PRESTART. +Defaults to DEFAULT_PRESTART. - Whether to prestart the threads +Whether to prestart the threads |`thread-name-prefix` |string |{nbsp} |Name prefix for threads in this thread pool executor. - Defaults to DEFAULT_THREAD_NAME_PREFIX. +Defaults to DEFAULT_THREAD_NAME_PREFIX. - Prefix of a thread name +Prefix of a thread name |`virtual-threads` |boolean |{nbsp} |When configured to `true`, an unbounded virtual executor service (project Loom) will be used. - If enabled, all other configuration options of this executor service are ignored! +If enabled, all other configuration options of this executor service are ignored! - Whether to use virtual threads or not, defaults to `false` +Whether to use virtual threads or not, defaults to `false` |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_common_pki_Keys.adoc b/docs/src/main/asciidoc/config/io_helidon_common_pki_Keys.adoc index 73ac006f60d..0fa04a3f930 100644 --- a/docs/src/main/asciidoc/config/io_helidon_common_pki_Keys.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_common_pki_Keys.adoc @@ -43,15 +43,15 @@ Type: link:{javadoc-base-url}/io.helidon.common.pki/io/helidon/common/pki/Keys.h |key |type |default value |description |`keystore` |xref:{rootdir}/config/io_helidon_common_pki_KeystoreKeys.adoc[KeystoreKeys] |{nbsp} |Configure keys from a keystore. - Once the config object is built, this option will ALWAYS be empty. All keys from the keystore will be - populated to privateKey(), publicKey(), publicCert() etc. +Once the config object is built, this option will ALWAYS be empty. All keys from the keystore will be +populated to privateKey(), publicKey(), publicCert() etc. - Keystore configuration +Keystore configuration |`pem` |xref:{rootdir}/config/io_helidon_common_pki_PemKeys.adoc[PemKeys] |{nbsp} |Configure keys from pem file(s). - Once the config object is built, this option will ALWAYS be empty. All keys from the keystore will be - populated to privateKey(), publicKey(), publicCert() etc. +Once the config object is built, this option will ALWAYS be empty. All keys from the keystore will be +populated to privateKey(), publicKey(), publicCert() etc. - Pem based definition +Pem based definition |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_common_pki_KeystoreKeys.adoc b/docs/src/main/asciidoc/config/io_helidon_common_pki_KeystoreKeys.adoc index 879150c5ae8..ef3721069cd 100644 --- a/docs/src/main/asciidoc/config/io_helidon_common_pki_KeystoreKeys.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_common_pki_KeystoreKeys.adoc @@ -41,7 +41,7 @@ Type: link:{javadoc-base-url}/io.helidon.common.pki/io/helidon/common/pki/Keysto |`resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Keystore resource definition. - Keystore resource, from file path, classpath, URL etc. +Keystore resource, from file path, classpath, URL etc. |=== @@ -55,31 +55,31 @@ Type: link:{javadoc-base-url}/io.helidon.common.pki/io/helidon/common/pki/Keysto |`cert-chain.alias` |string |{nbsp} |Alias of an X.509 chain. - Alias of certificate chain in the keystore +Alias of certificate chain in the keystore |`cert.alias` |string |{nbsp} |Alias of X.509 certificate of public key. - Used to load both the certificate and public key. +Used to load both the certificate and public key. - Alias under which the certificate is stored in the keystore +Alias under which the certificate is stored in the keystore |`key.alias` |string |{nbsp} |Alias of the private key in the keystore. - Alias of the key in the keystore +Alias of the key in the keystore |`key.passphrase` |char[] |{nbsp} |Pass-phrase of the key in the keystore (used for private keys). - This is (by default) the same as keystore passphrase - only configure - if it differs from keystore passphrase. +This is (by default) the same as keystore passphrase - only configure +if it differs from keystore passphrase. - Pass-phrase of the key +Pass-phrase of the key |`passphrase` |char[] |{nbsp} |Pass-phrase of the keystore (supported with JKS and PKCS12 keystores). - Keystore password to use +Keystore password to use |`trust-store` |boolean |`false` |If you want to build a trust store, call this method to add all - certificates present in the keystore to certificate list. +certificates present in the keystore to certificate list. - Whether this is a trust store +Whether this is a trust store |`type` |string |`PKCS12` |Set type of keystore. - Defaults to DEFAULT_KEYSTORE_TYPE, - expected are other keystore types supported by java then can store keys under aliases. +Defaults to DEFAULT_KEYSTORE_TYPE, +expected are other keystore types supported by java then can store keys under aliases. - Keystore type to load the key +Keystore type to load the key |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_common_pki_PemKeys.adoc b/docs/src/main/asciidoc/config/io_helidon_common_pki_PemKeys.adoc index 0ce01213cc4..86165efb690 100644 --- a/docs/src/main/asciidoc/config/io_helidon_common_pki_PemKeys.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_common_pki_PemKeys.adoc @@ -44,20 +44,20 @@ Type: link:{javadoc-base-url}/io.helidon.common.pki/io/helidon/common/pki/PemKey |`cert-chain.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Load certificate chain from PEM resource. - Resource (e.g. classpath, file path, URL etc.) +Resource (e.g. classpath, file path, URL etc.) |`certificates.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Read one or more certificates in PEM format from a resource definition. Used eg: in a trust store. - Key resource (file, classpath, URL etc.) +Key resource (file, classpath, URL etc.) |`key.passphrase` |char[] |{nbsp} |Passphrase for private key. If the key is encrypted (and in PEM PKCS#8 format), this passphrase will be used to - decrypt it. +decrypt it. - Passphrase used to encrypt the private key +Passphrase used to encrypt the private key |`key.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Read a private key from PEM format from a resource definition. - Key resource (file, classpath, URL etc.) +Key resource (file, classpath, URL etc.) |`public-key.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Read a public key from PEM format from a resource definition. - Public key resource (file, classpath, URL etc.) +Public key resource (file, classpath, URL etc.) |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_common_socket_SocketOptions.adoc b/docs/src/main/asciidoc/config/io_helidon_common_socket_SocketOptions.adoc index 15582cb3901..c3b74f7d34d 100644 --- a/docs/src/main/asciidoc/config/io_helidon_common_socket_SocketOptions.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_common_socket_SocketOptions.adoc @@ -44,33 +44,33 @@ Type: link:{javadoc-base-url}/io.helidon.common.socket/io/helidon/common/socket/ |`connect-timeout` |Duration |`PT10S` |Socket connect timeout. Default is 10 seconds. - Connect timeout duration +Connect timeout duration |`read-timeout` |Duration |`PT30S` |Socket read timeout. Default is 30 seconds. - Read timeout duration +Read timeout duration |`socket-keep-alive` |boolean |`true` |Configure socket keep alive. - Default is `true`. +Default is `true`. - Keep alive - See java.net.StandardSocketOptions.SO_KEEPALIVE +Keep alive +See java.net.StandardSocketOptions.SO_KEEPALIVE |`socket-receive-buffer-size` |int |{nbsp} |Socket receive buffer size. - Buffer size, in bytes - See java.net.StandardSocketOptions.SO_RCVBUF +Buffer size, in bytes +See java.net.StandardSocketOptions.SO_RCVBUF |`socket-reuse-address` |boolean |`true` |Socket reuse address. - Default is `true`. +Default is `true`. - Whether to reuse address - See java.net.StandardSocketOptions.SO_REUSEADDR +Whether to reuse address +See java.net.StandardSocketOptions.SO_REUSEADDR |`socket-send-buffer-size` |int |{nbsp} |Socket send buffer size. - Buffer size, in bytes - See java.net.StandardSocketOptions.SO_SNDBUF +Buffer size, in bytes +See java.net.StandardSocketOptions.SO_SNDBUF |`tcp-no-delay` |boolean |`false` |This option may improve performance on some systems. - Default is `false`. +Default is `false`. - Whether to use TCP_NODELAY, defaults to `false` - See java.net.StandardSocketOptions.TCP_NODELAY +Whether to use TCP_NODELAY, defaults to `false` +See java.net.StandardSocketOptions.TCP_NODELAY |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_common_tls_RevocationConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_common_tls_RevocationConfig.adoc index 20c489ce277..3dd53382018 100644 --- a/docs/src/main/asciidoc/config/io_helidon_common_tls_RevocationConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_common_tls_RevocationConfig.adoc @@ -43,38 +43,38 @@ Type: link:{javadoc-base-url}/io.helidon.common.tls/io/helidon/common/tls/Revoca |key |type |default value |description |`check-only-end-entity` |boolean |`false` |Only check the revocation status of end-entity certificates. - Default value is `false`. +Default value is `false`. - Whether to check only end-entity certificates +Whether to check only end-entity certificates |`enabled` |boolean |`false` |Flag indicating whether this revocation config is enabled. - Enabled flag +Enabled flag |`fallback-enabled` |boolean |`true` |Enable fallback to the less preferred checking option. -
      - If the primary method for revocation checking fails to verify the revocation status of a certificate - (such as using a CRL or OCSP), the checker will attempt alternative methods. This option ensures - whether revocation checking is performed strictly according to the specified method, or should fallback - to the one less preferred. OCSP is preferred over the CRL by default. - Whether to allow fallback to the less preferred checking option +If the primary method for revocation checking fails to verify the revocation status of a certificate +(such as using a CRL or OCSP), the checker will attempt alternative methods. This option ensures +whether revocation checking is performed strictly according to the specified method, or should fallback +to the one less preferred. OCSP is preferred over the CRL by default. + +Whether to allow fallback to the less preferred checking option |`ocsp-responder-uri` |URI |{nbsp} |The URI that identifies the location of the OCSP responder. This - overrides the `ocsp.responderURL` security property and any - responder specified in a certificate's Authority Information Access - Extension, as defined in RFC 5280. +overrides the `ocsp.responderURL` security property and any +responder specified in a certificate's Authority Information Access +Extension, as defined in RFC 5280. - OCSP responder URI +OCSP responder URI |`prefer-crl-over-ocsp` |boolean |`false` |Prefer CRL over OCSP. - Default value is `false`. OCSP is preferred over the CRL by default. +Default value is `false`. OCSP is preferred over the CRL by default. - Whether to prefer CRL over OCSP +Whether to prefer CRL over OCSP |`soft-fail-enabled` |boolean |`false` |Allow revocation check to succeed if the revocation status cannot be - determined for one of the following reasons: +determined for one of the following reasons: - The CRL or OCSP response cannot be obtained because of a - network error. - + network error. + - The OCSP responder returns one of the following errors - specified in section 2.3 of RFC 2560: internalError or tryLater. + specified in section 2.3 of RFC 2560: internalError or tryLater. Whether soft fail is enabled diff --git a/docs/src/main/asciidoc/config/io_helidon_common_tls_Tls.adoc b/docs/src/main/asciidoc/config/io_helidon_common_tls_Tls.adoc index 0be141798c3..cd75173fc43 100644 --- a/docs/src/main/asciidoc/config/io_helidon_common_tls_Tls.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_common_tls_Tls.adoc @@ -44,75 +44,88 @@ Type: link:{javadoc-base-url}/io.helidon.common.tls/io/helidon/common/tls/Tls.ht |`cipher-suite` |string[] |{nbsp} |Enabled cipher suites for TLS communication. - Cipher suits to enable, by default (or if list is empty), all available cipher suites - are enabled -|`client-auth` |TlsClientAuth |`TlsClientAuth.NONE` |Configure requirement for mutual TLS. +Cipher suites to enable, by default (or if list is empty), all available cipher suites + are enabled +|`client-auth` |TlsClientAuth (REQUIRED, OPTIONAL, NONE) |`TlsClientAuth.NONE` |Configure requirement for mutual TLS. + +What type of mutual TLS to use, defaults to TlsClientAuth.NONE + +Allowed values: + +- `REQUIRED`: Mutual TLS is required. +Server MUST present a certificate trusted by the client, client MUST present a certificate trusted by the server. +This implies private key and trust configuration for both server and client. +- `OPTIONAL`: Mutual TLS is optional. +Server MUST present a certificate trusted by the client, client MAY present a certificate trusted by the server. +This implies private key configuration at least for server, trust configuration for at least client. +- `NONE`: Mutual TLS is disabled. +Server MUST present a certificate trusted by the client, client does not present a certificate. +This implies private key configuration for server, trust configuration for client. - What type of mutual TLS to use, defaults to TlsClientAuth.NONE |`enabled` |boolean |`true` |Flag indicating whether Tls is enabled. - Enabled flag +Enabled flag |`endpoint-identification-algorithm` |string |`HTTPS` |Identification algorithm for SSL endpoints. - Configure endpoint identification algorithm, or set to `NONE` - to disable endpoint identification (equivalent to hostname verification). - Defaults to Tls.ENDPOINT_IDENTIFICATION_HTTPS +Configure endpoint identification algorithm, or set to `NONE` + to disable endpoint identification (equivalent to hostname verification). + Defaults to Tls.ENDPOINT_IDENTIFICATION_HTTPS |`internal-keystore-provider` |string |{nbsp} |Provider of the key stores used internally to create a key and trust manager factories. - Keystore provider, if not defined, provider is not specified +Keystore provider, if not defined, provider is not specified |`internal-keystore-type` |string |{nbsp} |Type of the key stores used internally to create a key and trust manager factories. - Keystore type, defaults to java.security.KeyStore.getDefaultType() +Keystore type, defaults to java.security.KeyStore.getDefaultType() |`key-manager-factory-algorithm` |string |{nbsp} |Algorithm of the key manager factory used when private key is defined. - Defaults to javax.net.ssl.KeyManagerFactory.getDefaultAlgorithm(). +Defaults to javax.net.ssl.KeyManagerFactory.getDefaultAlgorithm(). - Algorithm to use +Algorithm to use |`manager` |io.helidon.common.tls.TlsManager (service provider interface) |{nbsp} |The Tls manager. If one is not explicitly defined in the config then a default manager will be created. - The tls manager of the tls instance - See ConfiguredTlsManager +The tls manager of the tls instance +See ConfiguredTlsManager |`private-key` |PrivateKey |{nbsp} |Private key to use. For server side TLS, this is required. - For client side TLS, this is optional (used when mutual TLS is enabled). +For client side TLS, this is optional (used when mutual TLS is enabled). - Private key to use +Private key to use |`protocol` |string |`TLS` |Configure the protocol used to obtain an instance of javax.net.ssl.SSLContext. - Protocol to use, defaults to DEFAULT_PROTOCOL +Protocol to use, defaults to DEFAULT_PROTOCOL |`protocols` |string[] |{nbsp} |Enabled protocols for TLS communication. - Example of valid values for `TLS` protocol: `TLSv1.3`, `TLSv1.2` +Example of valid values for `TLS` protocol: `TLSv1.3`, `TLSv1.2` - Protocols to enable, by default (or if list is empty), all available protocols are enabled +Protocols to enable, by default (or if list is empty), all available protocols are enabled |`provider` |string |{nbsp} |Use explicit provider to obtain an instance of javax.net.ssl.SSLContext. - Provider to use, defaults to none (only protocol() is used by default) +Provider to use, defaults to none (only protocol() is used by default) |`revocation` |xref:{rootdir}/config/io_helidon_common_tls_RevocationConfig.adoc[RevocationConfig] |{nbsp} |Certificate revocation check configuration. - Certificate revocation configuration +Certificate revocation configuration |`secure-random-algorithm` |string |{nbsp} |Algorithm to use when creating a new secure random. - Algorithm to use, by default uses java.security.SecureRandom constructor +Algorithm to use, by default uses java.security.SecureRandom constructor |`secure-random-provider` |string |{nbsp} |Provider to use when creating a new secure random. - When defined, secureRandomAlgorithm() must be defined as well. +When defined, secureRandomAlgorithm() must be defined as well. - Provider to use, by default no provider is specified +Provider to use, by default no provider is specified |`session-cache-size` |int |`20480` |SSL session cache size. - Session cache size, defaults to DEFAULT_SESSION_CACHE_SIZE. +Session cache size, defaults to DEFAULT_SESSION_CACHE_SIZE. |`session-timeout` |Duration |`PT24H` |SSL session timeout. - Session timeout, defaults to DEFAULT_SESSION_TIMEOUT. +Session timeout, defaults to DEFAULT_SESSION_TIMEOUT. |`trust` |X509Certificate[] |{nbsp} |List of certificates that form the trust manager. - Certificates to be trusted +Certificates to be trusted |`trust-all` |boolean |`false` |Trust any certificate provided by the other side of communication. - This is a dangerous setting: if set to `true`, any certificate will be accepted, throwing away - most of the security advantages of TLS. NEVER do this in production. +*This is a dangerous setting:* if set to `true`, any certificate will be accepted, throwing away +most of the security advantages of TLS. *NEVER* do this in production. - Whether to trust all certificates, do not use in production +Whether to trust all certificates, do not use in production |`trust-manager-factory-algorithm` |string |{nbsp} |Trust manager factory algorithm. - Algorithm to use +Algorithm to use |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_dbclient_jdbc_JdbcParametersConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_dbclient_jdbc_JdbcParametersConfig.adoc index 070a64f2c12..db6fe8a629c 100644 --- a/docs/src/main/asciidoc/config/io_helidon_dbclient_jdbc_JdbcParametersConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_dbclient_jdbc_JdbcParametersConfig.adoc @@ -49,41 +49,41 @@ parameters |key |type |default value |description |`set-object-for-java-time` |boolean |`true` |Set all `java.time` Date/Time values directly using java.sql.PreparedStatement.setObject(int, Object). - This option shall work fine for recent JDBC drivers. - Default value is `true`. +This option shall work fine for recent JDBC drivers. +Default value is `true`. - Whether to use java.sql.PreparedStatement.setObject(int, Object) for `java.time` Date/Time values +Whether to use java.sql.PreparedStatement.setObject(int, Object) for `java.time` Date/Time values |`string-binding-size` |int |`1024` |String values with length above this limit will be bound - using java.sql.PreparedStatement.setCharacterStream(int, java.io.Reader, int) - if useStringBinding() is set to `true`. - Default value is `1024`. +using java.sql.PreparedStatement.setCharacterStream(int, java.io.Reader, int) +if useStringBinding() is set to `true`. +Default value is `1024`. - String values length limit for java.io.CharArrayReader binding +String values length limit for java.io.CharArrayReader binding |`timestamp-for-local-time` |boolean |`true` |Use java.sql.PreparedStatement.setTimestamp(int, java.sql.Timestamp) - to set java.time.LocalTime values when `true` - or use java.sql.PreparedStatement.setTime(int, java.sql.Time) when `false`. - Default value is `true`. +to set java.time.LocalTime values when `true` +or use java.sql.PreparedStatement.setTime(int, java.sql.Time) when `false`. +Default value is `true`. This option is vendor specific. Most of the databases are fine with java.sql.Timestamp, - but for example SQL Server requires java.sql.Time. - This option does not apply when setObjectForJavaTime() is set to `true`. +but for example SQL Server requires java.sql.Time. +This option does not apply when setObjectForJavaTime() is set to `true`. - Whether to use java.sql.Timestamp instead of java.sql.Time - for java.time.LocalTime values +Whether to use java.sql.Timestamp instead of java.sql.Time + for java.time.LocalTime values |`use-byte-array-binding` |boolean |`true` |Use java.sql.PreparedStatement.setBinaryStream(int, java.io.InputStream, int) binding - for `byte[]` values. - Default value is `true`. +for `byte[]` values. +Default value is `true`. - Whether to use java.io.ByteArrayInputStream binding +Whether to use java.io.ByteArrayInputStream binding |`use-n-string` |boolean |`false` |Use SQL `NCHAR`, `NVARCHAR` or `LONGNVARCHAR` value conversion - for String values. - Default value is `false`. +for String values. +Default value is `false`. - Whether NString conversion is used +Whether NString conversion is used |`use-string-binding` |boolean |`true` |Use java.sql.PreparedStatement.setCharacterStream(int, java.io.Reader, int) binding - for String values with length above stringBindingSize() limit. - Default value is `true`. +for String values with length above stringBindingSize() limit. +Default value is `true`. - Whether to use java.io.CharArrayReader binding +Whether to use java.io.CharArrayReader binding |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Async.adoc b/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Async.adoc index c0a54be5be9..13d24ed588e 100644 --- a/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Async.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Async.adoc @@ -44,8 +44,8 @@ Type: link:{javadoc-base-url}/io.helidon.faulttolerance/io/helidon/faulttoleranc |`executor-name` |string |{nbsp} |Name of an executor service. This is only honored when service registry is used. - Name fo the java.util.concurrent.ExecutorService to lookup - See executor() +Name fo the java.util.concurrent.ExecutorService to lookup +See executor() |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Bulkhead.adoc b/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Bulkhead.adoc index 9f7027f1ca2..8a7645c5e00 100644 --- a/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Bulkhead.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Bulkhead.adoc @@ -45,14 +45,14 @@ This is a standalone configuration type, prefix from configuration root: `fault- |key |type |default value |description |`limit` |int |`10` |Maximal number of parallel requests going through this bulkhead. - When the limit is reached, additional requests are enqueued. +When the limit is reached, additional requests are enqueued. - Maximal number of parallel calls, defaults is DEFAULT_LIMIT +Maximal number of parallel calls, defaults is DEFAULT_LIMIT |`queue-length` |int |`10` |Maximal number of enqueued requests waiting for processing. - When the limit is reached, additional attempts to invoke - a request will receive a BulkheadException. +When the limit is reached, additional attempts to invoke +a request will receive a BulkheadException. - Length of the queue +Length of the queue |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_faulttolerance_CircuitBreaker.adoc b/docs/src/main/asciidoc/config/io_helidon_faulttolerance_CircuitBreaker.adoc index 9a4dd921426..ea06b3b349c 100644 --- a/docs/src/main/asciidoc/config/io_helidon_faulttolerance_CircuitBreaker.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_faulttolerance_CircuitBreaker.adoc @@ -46,24 +46,24 @@ This is a standalone configuration type, prefix from configuration root: `fault- |`delay` |Duration |`PT5S` |How long to wait before transitioning from open to half-open state. - Delay +Delay |`error-ratio` |int |`60` |How many failures out of 100 will trigger the circuit to open. - This is adapted to the volume() used to handle the window of requests. +This is adapted to the volume() used to handle the window of requests. If errorRatio is 40, and volume is 10, 4 failed requests will open the circuit. - Default is DEFAULT_ERROR_RATIO. +Default is DEFAULT_ERROR_RATIO. - Percent of failure that trigger the circuit to open - See volume() +Percent of failure that trigger the circuit to open +See volume() |`success-threshold` |int |`1` |How many successful calls will close a half-open circuit. - Nevertheless, the first failed call will open the circuit again. - Default is DEFAULT_SUCCESS_THRESHOLD. +Nevertheless, the first failed call will open the circuit again. +Default is DEFAULT_SUCCESS_THRESHOLD. - Number of calls +Number of calls |`volume` |int |`10` |Rolling window size used to calculate ratio of failed requests. - Default is DEFAULT_VOLUME. +Default is DEFAULT_VOLUME. - How big a window is used to calculate error errorRatio - See errorRatio() +How big a window is used to calculate error errorRatio +See errorRatio() |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Retry.adoc b/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Retry.adoc index b1784993715..58e69696b83 100644 --- a/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Retry.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Retry.adoc @@ -46,25 +46,25 @@ This is a standalone configuration type, prefix from configuration root: `fault- |`calls` |int |`3` |Number of calls (first try + retries). - Number of desired calls, must be 1 (means no retries) or higher. +Number of desired calls, must be 1 (means no retries) or higher. |`delay` |Duration |`PT0.2S` |Base delay between try and retry. - Defaults to `200 ms`. +Defaults to `200 ms`. - Delay between retries (combines with retry policy) +Delay between retries (combines with retry policy) |`delay-factor` |double |`-1.0` |Delay retry policy factor. If unspecified (value of `-1`), Jitter retry policy would be used, unless - jitter is also unspecified. +jitter is also unspecified. - Default when Retry.DelayingRetryPolicy is used is `2`. +Default when Retry.DelayingRetryPolicy is used is `2`. - Delay factor for delaying retry policy +Delay factor for delaying retry policy |`jitter` |Duration |`PT-1S` |Jitter for Retry.JitterRetryPolicy. If unspecified (value of `-1`), - delaying retry policy is used. If both this value, and delayFactor() are specified, delaying retry policy - would be used. +delaying retry policy is used. If both this value, and delayFactor() are specified, delaying retry policy +would be used. - Jitter +Jitter |`overall-timeout` |Duration |`PT1S` |Overall timeout of all retries combined. - Overall timeout +Overall timeout |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Timeout.adoc b/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Timeout.adoc index 1311988311f..d8a0ad4beeb 100644 --- a/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Timeout.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Timeout.adoc @@ -45,13 +45,13 @@ This is a standalone configuration type, prefix from configuration root: `fault- |key |type |default value |description |`current-thread` |boolean |`false` |Flag to indicate that code must be executed in current thread instead - of in an executor's thread. This flag is `false` by default. +of in an executor's thread. This flag is `false` by default. - whether to execute on current thread (`true`), or in an executor service (`false`}) +Whether to execute on current thread (`true`), or in an executor service (`false`}) |`timeout` |Duration |`PT10S` |Duration to wait before timing out. - Defaults to `10 seconds`. +Defaults to `10 seconds`. - Timeout +Timeout |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_http_RequestedUriDiscoveryContext.adoc b/docs/src/main/asciidoc/config/io_helidon_http_RequestedUriDiscoveryContext.adoc index c43c7416ba8..d1f5a96f870 100644 --- a/docs/src/main/asciidoc/config/io_helidon_http_RequestedUriDiscoveryContext.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_http_RequestedUriDiscoveryContext.adoc @@ -46,6 +46,19 @@ Type: link:{javadoc-base-url}/io.helidon.http/io/helidon/http/RequestedUriDiscov |`trusted-proxies` |xref:{rootdir}/config/io_helidon_common_configurable_AllowList.adoc[AllowList] |{nbsp} |Sets the trusted proxies for requested URI discovery for requests arriving on the socket. |`types` |RequestedUriDiscoveryType[] (FORWARDED, X_FORWARDED, HOST) |{nbsp} |Sets the discovery types for requested URI discovery for requests arriving on the socket. +Allowed values: + +- `FORWARDED`: The `io.helidon.http.Header#FORWARDED` header is used to discover the original requested URI. +- `X_FORWARDED`: The +`io.helidon.http.Header#X_FORWARDED_PROTO`, +`io.helidon.http.Header#X_FORWARDED_HOST`, +`io.helidon.http.Header#X_FORWARDED_PORT`, +`io.helidon.http.Header#X_FORWARDED_PREFIX` +headers are used to discover the original requested URI. +- `HOST`: This is the default, only the `io.helidon.http.Header#HOST` header is used to discover +requested URI. + + |=== // end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_http_encoding_ContentEncodingContext.adoc b/docs/src/main/asciidoc/config/io_helidon_http_encoding_ContentEncodingContext.adoc index fc67019499f..88ae5154b10 100644 --- a/docs/src/main/asciidoc/config/io_helidon_http_encoding_ContentEncodingContext.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_http_encoding_ContentEncodingContext.adoc @@ -43,9 +43,9 @@ Type: link:{javadoc-base-url}/io.helidon.http.encoding/io/helidon/http/encoding/ |key |type |default value |description |`content-encodings` |io.helidon.http.encoding.ContentEncoding[] (service provider interface) |{nbsp} |List of content encodings that should be used. - Encodings configured here have priority over encodings discovered through service loader. +Encodings configured here have priority over encodings discovered through service loader. - List of content encodings to be used (such as `gzip,deflate`) +List of content encodings to be used (such as `gzip,deflate`) |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_http_media_MediaContext.adoc b/docs/src/main/asciidoc/config/io_helidon_http_media_MediaContext.adoc index ffafeed8c35..a12f74de824 100644 --- a/docs/src/main/asciidoc/config/io_helidon_http_media_MediaContext.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_http_media_MediaContext.adoc @@ -44,16 +44,16 @@ Type: link:{javadoc-base-url}/io.helidon.http.media/io/helidon/http/media/MediaC |`fallback` |xref:{rootdir}/config/io_helidon_http_media_MediaContext.adoc[MediaContext] |{nbsp} |Existing context to be used as a fallback for this context. - Media context to use if supports configured on this request cannot provide a good result +Media context to use if supports configured on this request cannot provide a good result |`media-supports` |io.helidon.http.media.MediaSupport[] (service provider interface) |{nbsp} |Media supports to use. - This instance has priority over provider(s) discovered by service loader. - The providers are used in order of calling this method, where the first support added is the - first one to be queried for readers and writers. +This instance has priority over provider(s) discovered by service loader. +The providers are used in order of calling this method, where the first support added is the +first one to be queried for readers and writers. - Media supports +Media supports |`register-defaults` |boolean |`true` |Should we register defaults of Helidon, such as String media support. - Whether to register default media supports +Whether to register default media supports |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_integrations_neo4j_Neo4j.adoc b/docs/src/main/asciidoc/config/io_helidon_integrations_neo4j_Neo4j.adoc index 04274bfc301..5f36b7c4ee1 100644 --- a/docs/src/main/asciidoc/config/io_helidon_integrations_neo4j_Neo4j.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_integrations_neo4j_Neo4j.adoc @@ -54,6 +54,13 @@ Type: link:{javadoc-base-url}/io.helidon.integrations.neo4j/io/helidon/integrati |`metrics-enabled` |boolean |{nbsp} |Enable metrics. |`password` |string |{nbsp} |Create password. |`trust-strategy` |TrustStrategy (TRUST_ALL_CERTIFICATES, TRUST_CUSTOM_CA_SIGNED_CERTIFICATES, TRUST_SYSTEM_CA_SIGNED_CERTIFICATES) |{nbsp} |Set trust strategy. + +Allowed values: + +- `TRUST_ALL_CERTIFICATES`: Trust all. +- `TRUST_CUSTOM_CA_SIGNED_CERTIFICATES`: Trust custom certificates. +- `TRUST_SYSTEM_CA_SIGNED_CERTIFICATES`: Trust system CA. + |`uri` |string |{nbsp} |Create uri. |`username` |string |{nbsp} |Create username. diff --git a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_ConfigFileMethodConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_integrations_oci_ConfigFileMethodConfig.adoc index 854dcd47c2a..d69eb150a69 100644 --- a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_ConfigFileMethodConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_integrations_oci_ConfigFileMethodConfig.adoc @@ -44,10 +44,10 @@ Type: link:{javadoc-base-url}/io.helidon.integrations.oci/io/helidon/integration |`path` |string |{nbsp} |The OCI configuration profile path. - The OCI configuration profile path +The OCI configuration profile path |`profile` |string |`DEFAULT` |The OCI configuration/auth profile name. - The optional OCI configuration/auth profile name +The optional OCI configuration/auth profile name |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_ConfigMethodConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_integrations_oci_ConfigMethodConfig.adoc index dad71bd1e1d..1053716e1ec 100644 --- a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_ConfigMethodConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_integrations_oci_ConfigMethodConfig.adoc @@ -44,39 +44,38 @@ Type: link:{javadoc-base-url}/io.helidon.integrations.oci/io/helidon/integration |`fingerprint` |string |{nbsp} |The OCI authentication fingerprint. - This configuration property must be provided in order to set the API signing key's fingerprint. - See com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getFingerprint() for more details. +This configuration property must be provided in order to set the https://docs.oracle.com/en-us/iaas/Content/API/Concepts/apisigningkey.htm[API signing key's fingerprint]. +See com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getFingerprint() for more details. - The OCI authentication fingerprint +The OCI authentication fingerprint |`passphrase` |char[] |{nbsp} |The OCI authentication passphrase. - This property must be provided in order to set the - com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getPassphraseCharacters(). +This property must be provided in order to set the +com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getPassphraseCharacters(). - The OCI authentication passphrase +The OCI authentication passphrase |`private-key` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |The OCI authentication private key resource. - A resource can be defined as a resource on classpath, file on the file system, - base64 encoded text value in config, or plain-text value in config. +A resource can be defined as a resource on classpath, file on the file system, +base64 encoded text value in config, or plain-text value in config. - If not defined, we will use `.oci/oic_api_key.pem` file in user home directory. +If not defined, we will use `.oci/oic_api_key.pem` file in user home directory. - The OCI authentication key file +The OCI authentication key file |`region` |string |{nbsp} |The OCI region. - The OCI region +The OCI region |`tenant-id` |string |{nbsp} |The OCI tenant id. - This property must be provided in order to set the - com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getTenantId(). +This property must be provided in order to set the +com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getTenantId(). - The OCI tenant id +The OCI tenant id |`user-id` |string |{nbsp} |The OCI user id. - This property must be provided in order to set the - com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getUserId(). +This property must be provided in order to set the +com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getUserId(). - The OCI user id +The OCI user id |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_ImdsInstanceInfo.adoc b/docs/src/main/asciidoc/config/io_helidon_integrations_oci_ImdsInstanceInfo.adoc new file mode 100644 index 00000000000..5069d2b45ea --- /dev/null +++ b/docs/src/main/asciidoc/config/io_helidon_integrations_oci_ImdsInstanceInfo.adoc @@ -0,0 +1,75 @@ +/////////////////////////////////////////////////////////////////////////////// + + Copyright (c) 2024 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. + +/////////////////////////////////////////////////////////////////////////////// + +ifndef::rootdir[:rootdir: {docdir}/..] +:description: Configuration of io.helidon.integrations.oci.ImdsInstanceInfo +:keywords: helidon, config, io.helidon.integrations.oci.ImdsInstanceInfo +:basic-table-intro: The table below lists the configuration keys that configure io.helidon.integrations.oci.ImdsInstanceInfo +include::{rootdir}/includes/attributes.adoc[] + += ImdsInstanceInfo (integrations.oci) Configuration + +// tag::config[] + + +Type: link:{javadoc-base-url}/io.helidon.integrations.oci/io/helidon/integrations/oci/ImdsInstanceInfo.html[io.helidon.integrations.oci.ImdsInstanceInfo] + + + + +== Configuration options + + + +.Optional configuration options +[cols="3,3a,2,5a"] + +|=== +|key |type |default value |description + +|`canonical-region-name` |string |{nbsp} |Canonical Region Name. + +Canonical Region Name of where the Instance exists +|`compartment-id` |string |{nbsp} |Compartment Id. + +Compartment Id where the Instance was provisioned. +|`display-name` |string |{nbsp} |Display Name. + +Display Name of the Instance +|`fault-domain` |string |{nbsp} |Fault Domain Name. + +Fault Domain Name where the Instance exists +|`host-name` |string |{nbsp} |Host Name. + +Host Name of the Instance +|`json-object` |JsonObject |{nbsp} |Instance Data. + +Full information about the Instance as a jakarta.json.JsonObject +|`oci-ad-name` |string |{nbsp} |Oci Availability Domain Name. + +Physical Availaibility Domain Name where the Instance exists +|`region` |string |{nbsp} |Region Name. + +Short Region Name of where the Instance exists +|`tenant-id` |string |{nbsp} |Tenant Id. + +Tenant Id where the Instance was provisioned. + +|=== + +// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_OciConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_integrations_oci_OciConfig.adoc index 5868fa757b7..3f82d6f30f5 100644 --- a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_OciConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_integrations_oci_OciConfig.adoc @@ -44,62 +44,66 @@ This is a standalone configuration type, prefix from configuration root: `helido |=== |key |type |default value |description -|`allowed-atn-methods` |string[] |{nbsp} |List of attempted authentication strategies in case atnMethod() is set to ATN_METHOD_AUTO. +|`allowed-authentication-methods` |string[] |{nbsp} |List of attempted authentication strategies in case io.helidon.integrations.oci.OciConfig.authenticationMethod() is +set to AUTHENTICATION_METHOD_AUTO. - In case the list is empty, all available strategies will be tried, ordered by their io.helidon.common.Weight +In case the list is empty, all available strategies will be tried, ordered by their io.helidon.common.Weight - List of authentication strategies to be tried - See atnMethod() -|`atn-method` |string |`auto` |Authentication method to use. If the configured method is not available, an exception - would be thrown for OCI related services. +List of authentication strategies to be tried +See io.helidon.integrations.oci.OciConfig.authenticationMethod() +|`authentication-method` |string |`auto` |Authentication method to use. If the configured method is not available, an exception +would be thrown for OCI related services. - Known and supported authentication strategies for public OCI: +Known and supported authentication strategies for public OCI: -- ATN_METHOD_AUTO - use the list of allowedAtnMethods() (in the provided order), and choose - the first one - capable of providing data +- AUTHENTICATION_METHOD_AUTO - use the list of + io.helidon.integrations.oci.OciConfig.allowedAuthenticationMethods() + (in the provided order), and choose the first one capable of providing data - AuthenticationMethodConfig.METHOD - - use configuration of the application to obtain values needed to set up connectivity, uses - com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider + use configuration of the application to obtain values needed to set up connectivity, uses + com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider - AuthenticationMethodConfigFile.METHOD - use configuration file of OCI (`home/.oci/config`), uses - com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider + com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider - `resource-principal` - use identity of the OCI resource the service is executed on - (fn), uses - com.oracle.bmc.auth.ResourcePrincipalAuthenticationDetailsProvider, and is available in a - separate module `helidon-integrations-oci-authentication-resource` + (fn), uses + com.oracle.bmc.auth.ResourcePrincipalAuthenticationDetailsProvider, and is available in a + separate module `helidon-integrations-oci-authentication-resource` - `instance-principal` - use identity of the OCI instance the service is running on, uses - com.oracle.bmc.auth.InstancePrincipalsAuthenticationDetailsProvider, and is available in a - separate module `helidon-integrations-oci-authentication-resource` + com.oracle.bmc.auth.InstancePrincipalsAuthenticationDetailsProvider, and is available in a + separate module `helidon-integrations-oci-authentication-resource` - `workload` - use workload identity of the OCI Kubernetes workload, available in a - separate module `helidon-integrations-oci-authentication-workload` + separate module `helidon-integrations-oci-authentication-workload` The authentication method to apply -|`atn-timeout` |Duration |`PT10S` |Timeout of authentication operations, where applicable. - This is a timeout for each operation (if there are retries, each timeout will be this duration). - Defaults to 10 seconds. +|`authentication-timeout` |Duration |`PT10S` |Timeout of authentication operations, where applicable. +This is a timeout for each operation (if there are retries, each timeout will be this duration). +Defaults to 10 seconds. - Authentication operation timeout +Authentication operation timeout |`authentication.config` |xref:{rootdir}/config/io_helidon_integrations_oci_ConfigMethodConfig.adoc[ConfigMethodConfig] |{nbsp} |Config method configuration (if provided and used). - Information needed for config atnMethod() +Information needed for config io.helidon.integrations.oci.OciConfig.authenticationMethod() |`authentication.config-file` |xref:{rootdir}/config/io_helidon_integrations_oci_ConfigFileMethodConfig.adoc[ConfigFileMethodConfig] |{nbsp} |Config file method configuration (if provided and used). - Information to customize config for atnMethod() +Information to customize config for io.helidon.integrations.oci.OciConfig.authenticationMethod() |`authentication.session-token` |xref:{rootdir}/config/io_helidon_integrations_oci_SessionTokenMethodConfig.adoc[SessionTokenMethodConfig] |{nbsp} |Session token method configuration (if provided and used). - Information to customize config for atnMethod() +Information to customize config for io.helidon.integrations.oci.OciConfig.authenticationMethod() |`imds-base-uri` |URI |{nbsp} |The OCI IMDS URI (http URL pointing to the metadata service, if customization needed). - The OCI IMDS URI -|`imds-timeout` |Duration |`PT0.1S` |The OCI IMDS connection timeout. This is used to auto-detect availability. +The OCI IMDS URI +|`imds-detect-retries` |int |{nbsp} |Customize the number of retries to contact IMDS service. - This configuration property is used when attempting to connect to the metadata service. +Number of retries, each provider has its own defaults +|`imds-timeout` |Duration |`PT1S` |The OCI IMDS connection timeout. This is used to auto-detect availability. - The OCI IMDS connection timeout +This configuration property is used when attempting to connect to the metadata service. + +The OCI IMDS connection timeout |`region` |Region |{nbsp} |Explicit region. The configured region will be used by region provider. - This may be ignored by authentication detail providers, as in most cases region is provided by them. +This may be ignored by authentication detail providers, as in most cases region is provided by them. - Explicit region +Explicit region |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_SessionTokenMethodConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_integrations_oci_SessionTokenMethodConfig.adoc index 903dd8898c7..f54e475e444 100644 --- a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_SessionTokenMethodConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_integrations_oci_SessionTokenMethodConfig.adoc @@ -44,62 +44,61 @@ Type: link:{javadoc-base-url}/io.helidon.integrations.oci/io/helidon/integration |`fingerprint` |string |{nbsp} |The OCI authentication fingerprint. - This configuration property must be provided in order to set the API signing key's fingerprint. - See com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getFingerprint() for more details. +This configuration property must be provided in order to set the https://docs.oracle.com/en-us/iaas/Content/API/Concepts/apisigningkey.htm[API signing key's fingerprint]. +See com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getFingerprint() for more details. - The OCI authentication fingerprint +The OCI authentication fingerprint |`initial-refresh-delay` |Duration |{nbsp} |Delay of the first refresh. - Defaults to 0, to refresh immediately (implemented in the authentication details provider). +Defaults to 0, to refresh immediately (implemented in the authentication details provider). - Initial refresh delay - See SessionTokenAuthenticationDetailsProviderBuilder.initialRefreshDelay(long) +Initial refresh delay +See com.oracle.bmc.auth.SessionTokenAuthenticationDetailsProvider.SessionTokenAuthenticationDetailsProviderBuilder.initialRefreshDelay(long) |`passphrase` |char[] |{nbsp} |The OCI authentication passphrase. - This property must be provided in order to set the - com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getPassphraseCharacters(). +This property must be provided in order to set the +com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getPassphraseCharacters(). - The OCI authentication passphrase +The OCI authentication passphrase |`private-key-path` |Path |{nbsp} |The OCI authentication private key resource. - A resource can be defined as a resource on classpath, file on the file system, - base64 encoded text value in config, or plain-text value in config. +A resource can be defined as a resource on classpath, file on the file system, +base64 encoded text value in config, or plain-text value in config. - If not defined, we will use `".oci/sessions/DEFAULT/oci_api_key.pem` file in user home directory. +If not defined, we will use `".oci/sessions/DEFAULT/oci_api_key.pem` file in user home directory. - The OCI authentication key file +The OCI authentication key file |`refresh-period` |Duration |{nbsp} |Refresh period, i.e. how often refresh occurs. - Defaults to 55 minutes (implemented in the authentication details provider). +Defaults to 55 minutes (implemented in the authentication details provider). - Refresh period - See SessionTokenAuthenticationDetailsProviderBuilder.refreshPeriod(long) +Refresh period +See com.oracle.bmc.auth.SessionTokenAuthenticationDetailsProvider.SessionTokenAuthenticationDetailsProviderBuilder.refreshPeriod(long) |`region` |string |{nbsp} |The OCI region. - The OCI region +The OCI region |`session-lifetime-hours` |long |{nbsp} |Maximal lifetime of a session. - Defaults to (and maximum is) 24 hours. - Can only be set to a lower value. +Defaults to (and maximum is) 24 hours. +Can only be set to a lower value. - Lifetime of a session in hours +Lifetime of a session in hours |`session-token` |string |{nbsp} |Session token value. - If both this value, and sessionTokenPath() is defined, this value is used. +If both this value, and sessionTokenPath() is defined, this value is used. - Session token +Session token |`session-token-path` |Path |{nbsp} |Session token path. - If both this value, and sessionToken() is defined, the value of sessionToken() is used. +If both this value, and sessionToken() is defined, the value of sessionToken() is used. - Session token path +Session token path |`tenant-id` |string |{nbsp} |The OCI tenant id. - This property must be provided in order to set the - com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getTenantId(). +This property must be provided in order to set the +com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getTenantId(). - The OCI tenant id +The OCI tenant id |`user-id` |string |{nbsp} |The OCI user id. - This property must be provided in order to set the - com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getUserId(). +This property must be provided in order to set the +com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getUserId(). - The OCI user id +The OCI user id |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_metrics_OciMetricsSupport.adoc b/docs/src/main/asciidoc/config/io_helidon_integrations_oci_metrics_OciMetricsSupport.adoc index b75534ef5a4..4a2ca3977e1 100644 --- a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_metrics_OciMetricsSupport.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_integrations_oci_metrics_OciMetricsSupport.adoc @@ -43,29 +43,29 @@ Type: link:{javadoc-base-url}/io.helidon.integrations.oci.metrics/io/helidon/int |key |type |default value |description |`batch-delay` |long |`1` |Sets the delay interval if metrics are posted in batches - (defaults to DEFAULT_BATCH_DELAY). +(defaults to DEFAULT_BATCH_DELAY). |`batch-size` |int |`50` |Sets the maximum no. of metrics to send in a batch - (defaults to DEFAULT_BATCH_SIZE). +(defaults to DEFAULT_BATCH_SIZE). |`compartment-id` |string |{nbsp} |Sets the compartment ID. |`delay` |long |`60` |Sets the delay interval between metric posting - (defaults to DEFAULT_SCHEDULER_DELAY). +(defaults to DEFAULT_SCHEDULER_DELAY). |`description-enabled` |boolean |`true` |Sets whether the description should be enabled or not. - Defaults to `true`. - + Defaults to `true`. + |`enabled` |boolean |`true` |Sets whether metrics transmission to OCI is enabled. - Defaults to `true`. - + Defaults to `true`. + |`initial-delay` |long |`1` |Sets the initial delay before metrics are sent to OCI - (defaults to DEFAULT_SCHEDULER_INITIAL_DELAY). +(defaults to DEFAULT_SCHEDULER_INITIAL_DELAY). |`namespace` |string |{nbsp} |Sets the namespace. |`resource-group` |string |{nbsp} |Sets the resource group. |`scheduling-time-unit` |TimeUnit (NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS) |`TimeUnit.SECONDS` |Sets the time unit applied to the initial delay and delay values (defaults to `TimeUnit.SECONDS`). |`scopes` |String[] |`All scopes` |Sets which metrics scopes (e.g., base, vendor, application) should be sent to OCI. - If this method is never invoked, defaults to all scopes. - + If this method is never invoked, defaults to all scopes. + |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_sdk_runtime_OciConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_integrations_oci_sdk_runtime_OciConfig.adoc index d3f52799a44..ea125b939c9 100644 --- a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_sdk_runtime_OciConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_integrations_oci_sdk_runtime_OciConfig.adoc @@ -45,135 +45,152 @@ This is a standalone configuration type, prefix from configuration root: `oci` |key |type |default value |description |`auth-strategies` |string[] (auto, config, config-file, instance-principals, resource-principal) |{nbsp} |The list of authentication strategies that will be attempted by - com.oracle.bmc.auth.BasicAuthenticationDetailsProvider when one is - called for. This is only used if authStrategy() is not present. +com.oracle.bmc.auth.AbstractAuthenticationDetailsProvider when one is +called for. This is only used if authStrategy() is not present. - `auto` - if present in the list, or if no value - for this property exists. + for this property exists. - `config` - the - com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider - will be used, customized with other configuration - properties described here. + com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider + will be used, customized with other configuration + properties described here. - `config-file` - the - com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider - will be used, customized with other configuration - properties described here. + com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider + will be used, customized with other configuration + properties described here. - `instance-principals` - the - com.oracle.bmc.auth.InstancePrincipalsAuthenticationDetailsProvider - will be used. + com.oracle.bmc.auth.InstancePrincipalsAuthenticationDetailsProvider + will be used. - `resource-principal` - the - com.oracle.bmc.auth.ResourcePrincipalAuthenticationDetailsProvider - will be used. + com.oracle.bmc.auth.ResourcePrincipalAuthenticationDetailsProvider + will be used. If there are more than one strategy descriptors defined, the - first one that is deemed to be available/suitable will be used and all others will be ignored. +first one that is deemed to be available/suitable will be used and all others will be ignored. + +The list of authentication strategies that will be applied, defaulting to `auto` +See io.helidon.integrations.oci.sdk.runtime.OciAuthenticationDetailsProvider.AuthStrategy + +Allowed values: + +- `auto`: auto select first applicable +- `config`: simple authentication provider +- `config-file`: config file authentication provider +- `instance-principals`: instance principals authentication provider +- `resource-principal`: resource principal authentication provider - The list of authentication strategies that will be applied, defaulting to `auto` - See io.helidon.integrations.oci.sdk.runtime.OciAuthenticationDetailsProvider.AuthStrategy |`auth-strategy` |string (auto, config, config-file, instance-principals, resource-principal) |{nbsp} |The singular authentication strategy to apply. This will be preferred over authStrategies() if both are - present. +present. + +The singular authentication strategy to be applied + +Allowed values: + +- `auto`: auto select first applicable +- `config`: simple authentication provider +- `config-file`: config file authentication provider +- `instance-principals`: instance principals authentication provider +- `resource-principal`: resource principals authentication provider - The singular authentication strategy to be applied |`auth.fingerprint` |string |{nbsp} |The OCI authentication fingerprint. - This configuration property has an effect only when `config` is, explicitly or implicitly, - present in the value for the authStrategies(). This is also known as simpleConfigIsPresent(). - When it is present, this property must be provided in order to set the API signing key's fingerprint. - See com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getFingerprint() for more details. +This configuration property has an effect only when `config` is, explicitly or implicitly, +present in the value for the authStrategies(). This is also known as simpleConfigIsPresent(). +When it is present, this property must be provided in order to set the https://docs.oracle.com/en-us/iaas/Content/API/Concepts/apisigningkey.htm[API signing key's fingerprint]. +See com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getFingerprint() for more details. - The OCI authentication fingerprint +The OCI authentication fingerprint |`auth.keyFile` |string |`oci_api_key.pem` |The OCI authentication key file. - This configuration property has an effect only when `config` is, explicitly or implicitly, - present in the value for the authStrategies(). This is also known as simpleConfigIsPresent(). - When it is present, this property must be provided in order to set the - com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getPrivateKey(). This file must exist in the - `user.home` directory. Alternatively, this property can be set using either authPrivateKey() or - using authPrivateKeyPath(). +This configuration property has an effect only when `config` is, explicitly or implicitly, +present in the value for the authStrategies(). This is also known as simpleConfigIsPresent(). +When it is present, this property must be provided in order to set the +com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getPrivateKey(). This file must exist in the +`user.home` directory. Alternatively, this property can be set using either authPrivateKey() or +using authPrivateKeyPath(). - The OCI authentication key file +The OCI authentication key file |`auth.passphrase` |char[] |{nbsp} |The OCI authentication passphrase. - This configuration property has an effect only when `config` is, explicitly or implicitly, - present in the value for the authStrategies(). This is also known as simpleConfigIsPresent(). - When it is present, this property must be provided in order to set the - com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getPassphraseCharacters(). +This configuration property has an effect only when `config` is, explicitly or implicitly, +present in the value for the authStrategies(). This is also known as simpleConfigIsPresent(). +When it is present, this property must be provided in order to set the +com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getPassphraseCharacters(). - The OCI authentication passphrase +The OCI authentication passphrase |`auth.private-key` |char[] |{nbsp} |The OCI authentication private key. - This configuration property has an effect only when `config` is, explicitly or implicitly, - present in the value for the authStrategies(). This is also known as simpleConfigIsPresent(). - When it is present, this property must be provided in order to set the - com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getPrivateKey(). Alternatively, this property - can be set using either authKeyFile() residing in the `user.home` directory, or using - authPrivateKeyPath(). +This configuration property has an effect only when `config` is, explicitly or implicitly, +present in the value for the authStrategies(). This is also known as simpleConfigIsPresent(). +When it is present, this property must be provided in order to set the +com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getPrivateKey(). Alternatively, this property +can be set using either authKeyFile() residing in the `user.home` directory, or using +authPrivateKeyPath(). - The OCI authentication private key +The OCI authentication private key |`auth.private-key-path` |string |{nbsp} |The OCI authentication key file path. - This configuration property has an effect only when `config` is, explicitly or implicitly, - present in the value for the authStrategies(). This is also known as simpleConfigIsPresent(). - When it is present, this property must be provided in order to set the - com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getPrivateKey(). This file path is - an alternative for using authKeyFile() where the file must exist in the `user.home` directory. - Alternatively, this property can be set using authPrivateKey(). +This configuration property has an effect only when `config` is, explicitly or implicitly, +present in the value for the authStrategies(). This is also known as simpleConfigIsPresent(). +When it is present, this property must be provided in order to set the +com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getPrivateKey(). This file path is +an alternative for using authKeyFile() where the file must exist in the `user.home` directory. +Alternatively, this property can be set using authPrivateKey(). - The OCI authentication key file path +The OCI authentication key file path |`auth.region` |string |{nbsp} |The OCI region. - This configuration property has an effect only when `config` is, explicitly or implicitly, - present in the value for the authStrategies(). This is also known as simpleConfigIsPresent(). - When it is present, either this property or com.oracle.bmc.auth.RegionProvider must be provide a value in order - to set the com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider.getRegion(). +This configuration property has an effect only when `config` is, explicitly or implicitly, +present in the value for the authStrategies(). This is also known as simpleConfigIsPresent(). +When it is present, either this property or com.oracle.bmc.auth.RegionProvider must be provide a value in order +to set the com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider.getRegion(). - The OCI region +The OCI region |`auth.tenant-id` |string |{nbsp} |The OCI tenant id. - This configuration property has an effect only when `config` is, explicitly or implicitly, - present in the value for the authStrategies(). This is also known as simpleConfigIsPresent(). - When it is present, this property must be provided in order to set the - com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider.getTenantId(). +This configuration property has an effect only when `config` is, explicitly or implicitly, +present in the value for the authStrategies(). This is also known as simpleConfigIsPresent(). +When it is present, this property must be provided in order to set the +com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider.getTenantId(). - The OCI tenant id +The OCI tenant id |`auth.user-id` |string |{nbsp} |The OCI user id. - This configuration property has an effect only when `config` is, explicitly or implicitly, - present in the value for the authStrategies(). - When it is present, this property must be provided in order to set the - com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider.getUserId(). +This configuration property has an effect only when `config` is, explicitly or implicitly, +present in the value for the authStrategies(). +When it is present, this property must be provided in order to set the +com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider.getUserId(). - The OCI user id +The OCI user id |`config.path` |string |{nbsp} |The OCI configuration profile path. - This configuration property has an effect only when `config-file` is, explicitly or implicitly, - present in the value for the authStrategies(). This is also known as fileConfigIsPresent(). - When it is present, this property must also be present and then the - com.oracle.bmc.ConfigFileReader.parse(String) - method will be passed this value. It is expected to be passed with a - valid OCI configuration file path. +This configuration property has an effect only when `config-file` is, explicitly or implicitly, +present in the value for the authStrategies(). This is also known as fileConfigIsPresent(). +When it is present, this property must also be present and then the +com.oracle.bmc.ConfigFileReader.parse(String) +method will be passed this value. It is expected to be passed with a +valid OCI configuration file path. - The OCI configuration profile path +The OCI configuration profile path |`config.profile` |string |`DEFAULT` |The OCI configuration/auth profile name. - This configuration property has an effect only when `config-file` is, explicitly or implicitly, - present in the value for the authStrategies(). This is also known as fileConfigIsPresent(). - When it is present, this property may also be optionally provided in order to override the default - DEFAULT_PROFILE_NAME. +This configuration property has an effect only when `config-file` is, explicitly or implicitly, +present in the value for the authStrategies(). This is also known as fileConfigIsPresent(). +When it is present, this property may also be optionally provided in order to override the default +DEFAULT_PROFILE_NAME. - The optional OCI configuration/auth profile name +The optional OCI configuration/auth profile name |`imds.hostname` |string |`169.254.169.254` |The OCI IMDS hostname. - This configuration property is used to identify the metadata service url. +This configuration property is used to identify the metadata service url. - The OCI IMDS hostname +The OCI IMDS hostname |`imds.timeout.milliseconds` |Duration |`PT0.1S` |The OCI IMDS connection timeout. This is used to auto-detect availability. - This configuration property is used when attempting to connect to the metadata service. +This configuration property is used when attempting to connect to the metadata service. - The OCI IMDS connection timeout - See OciAvailability +The OCI IMDS connection timeout +See OciAvailability |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_tls_certificates_OciCertificatesTlsManager.adoc b/docs/src/main/asciidoc/config/io_helidon_integrations_oci_tls_certificates_OciCertificatesTlsManager.adoc index 3cac3de9438..e2727ce4d68 100644 --- a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_tls_certificates_OciCertificatesTlsManager.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_integrations_oci_tls_certificates_OciCertificatesTlsManager.adoc @@ -44,32 +44,32 @@ Type: link:{javadoc-base-url}/io.helidon.integrations.oci.tls.certificates/io/he |`ca-ocid` |string |{nbsp} |The Certificate Authority OCID. - Certificate authority OCID +Certificate authority OCID |`cert-ocid` |string |{nbsp} |The Certificate OCID. - Certificate OCID +Certificate OCID |`compartment-ocid` |string |{nbsp} |The OCID of the compartment the services are in. - The compartment OCID +The compartment OCID |`key-ocid` |string |{nbsp} |The Key OCID. - Key OCID +Key OCID |`key-password` |Supplier |{nbsp} |The Key password. - Key password +Key password |`schedule` |string |{nbsp} |The schedule for trigger a reload check, testing whether there is a new io.helidon.common.tls.Tls instance - available. +available. - The schedule for reload +The schedule for reload |`vault-crypto-endpoint` |URI |{nbsp} |The address to use for the OCI Key Management Service / Vault crypto usage. - Each OCI Vault has public crypto and management endpoints. We need to specify the crypto endpoint of the vault we are - rotating the private keys in. The implementation expects both client and server to store the private key in the same vault. +Each OCI Vault has public crypto and management endpoints. We need to specify the crypto endpoint of the vault we are +rotating the private keys in. The implementation expects both client and server to store the private key in the same vault. - The address for the key management service / vault crypto usage +The address for the key management service / vault crypto usage |`vault-management-endpoint` |URI |{nbsp} |The address to use for the OCI Key Management Service / Vault management usage. - The crypto endpoint of the vault we are rotating the private keys in. +The crypto endpoint of the vault we are rotating the private keys in. - The address for the key management service / vault management usage +The address for the key management service / vault management usage |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_integrations_openapi_ui_OpenApiUi.adoc b/docs/src/main/asciidoc/config/io_helidon_integrations_openapi_ui_OpenApiUi.adoc index 53fd3897ad5..b03520e095d 100644 --- a/docs/src/main/asciidoc/config/io_helidon_integrations_openapi_ui_OpenApiUi.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_integrations_openapi_ui_OpenApiUi.adoc @@ -44,13 +44,13 @@ Type: link:{javadoc-base-url}/io.helidon.integrations.openapi.ui/io/helidon/inte |`enabled` |boolean |`true` |Sets whether the service should be enabled. - `true` if enabled, `false` otherwise +`true` if enabled, `false` otherwise |`options` |Map<string, string> |{nbsp} |Merges implementation-specific UI options. - Options for the UI to merge +Options for the UI to merge |`web-context` |string |{nbsp} |Full web context (not just the suffix). - Full web context path +Full web context path |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_metrics_api_KeyPerformanceIndicatorMetricsConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_metrics_api_KeyPerformanceIndicatorMetricsConfig.adoc index 64b33e47f53..9b1de363e07 100644 --- a/docs/src/main/asciidoc/config/io_helidon_metrics_api_KeyPerformanceIndicatorMetricsConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_metrics_api_KeyPerformanceIndicatorMetricsConfig.adoc @@ -44,10 +44,10 @@ Type: link:{javadoc-base-url}/io.helidon.metrics.api/io/helidon/metrics/api/KeyP |`extended` |boolean |`false` |Whether KPI extended metrics are enabled. - True if KPI extended metrics are enabled; false otherwise +True if KPI extended metrics are enabled; false otherwise |`long-running-requests.threshold` |Duration |`PT10S` |Threshold in ms that characterizes whether a request is long running. - Threshold in ms indicating a long-running request +Threshold in ms indicating a long-running request |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_metrics_api_MetricsConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_metrics_api_MetricsConfig.adoc index 75ec7695bea..154b8c1c7c0 100644 --- a/docs/src/main/asciidoc/config/io_helidon_metrics_api_MetricsConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_metrics_api_MetricsConfig.adoc @@ -46,38 +46,46 @@ This is a standalone configuration type, prefix from configuration root: `metric |`app-name` |string |{nbsp} |Value for the application tag to be added to each meter ID. - Application tag value +Application tag value |`app-tag-name` |string |{nbsp} |Name for the application tag to be added to each meter ID. - Application tag name +Application tag name |`enabled` |boolean |`true` |Whether metrics functionality is enabled. - If metrics are configured to be enabled +If metrics are configured to be enabled |[.line-through]#`gc-time-type`# |GcTimeType (GAUGE, COUNTER) |`GcTimeType.COUNTER` |*Deprecated* Whether the `gc.time` meter should be registered as a gauge (vs. a counter). - The `gc.time` meter is inspired by the MicroProfile Metrics spec, in which the meter was originally checked to - be a counter but starting in 5.1 was checked be a gauge. For the duration of Helidon 4.x users can choose which - type of meter Helidon registers for `gc.time`. - The type of meter to use for registering `gc.time` - @deprecated Provided for backward compatibility only; no replacement +The `gc.time` meter is inspired by the MicroProfile Metrics spec, in which the meter was originally checked to +be a counter but starting in 5.1 was checked be a gauge. For the duration of Helidon 4.x users can choose which +type of meter Helidon registers for `gc.time`. +The type of meter to use for registering `gc.time` +@deprecated Provided for backward compatibility only; no replacement + +Allowed values: + +- `GAUGE`: Implement the meter as a gauge. This is backward-incompatible with Helidon 4.0.x releases but complies with +MicroProfile 5.1. +- `COUNTER`: Implement the meter as a counter. This is backward-compatible with Helidon 4.0.x releases but does not comply with +MicroProfile 5.1. + |`key-performance-indicators` |xref:{rootdir}/config/io_helidon_metrics_api_KeyPerformanceIndicatorMetricsConfig.adoc[KeyPerformanceIndicatorMetricsConfig] |{nbsp} |Key performance indicator metrics settings. - Key performance indicator metrics settings +Key performance indicator metrics settings |`permit-all` |boolean |`true` |Whether to allow anybody to access the endpoint. - Whether to permit access to metrics endpoint to anybody, defaults to `true` - See roles() +Whether to permit access to metrics endpoint to anybody, defaults to `true` +See roles() |`rest-request-enabled` |boolean |`false` |Whether automatic REST request metrics should be measured. - True/false +True/false |`roles` |string[] |`observe` |Hints for role names the user is expected to be in. - List of hints +List of hints |`scoping` |xref:{rootdir}/config/io_helidon_metrics_api_ScopingConfig.adoc[ScopingConfig] |{nbsp} |Settings related to scoping management. - Scoping settings +Scoping settings |`tags` |xref:{rootdir}/config/io_helidon_metrics_api_Tag.adoc[Tag[]] |{nbsp} |Global tags. - Name/value pairs for global tags +Name/value pairs for global tags |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_metrics_api_ScopeConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_metrics_api_ScopeConfig.adoc index f1caf5e0661..633a78c55d2 100644 --- a/docs/src/main/asciidoc/config/io_helidon_metrics_api_ScopeConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_metrics_api_ScopeConfig.adoc @@ -44,16 +44,16 @@ Type: link:{javadoc-base-url}/io.helidon.metrics.api/io/helidon/metrics/api/Scop |`enabled` |boolean |`true` |Whether the scope is enabled. - If the scope is enabled +If the scope is enabled |`filter.exclude` |Pattern |{nbsp} |Regular expression for meter names to exclude. - Exclude expression +Exclude expression |`filter.include` |Pattern |{nbsp} |Regular expression for meter names to include. - Include expression +Include expression |`name` |string |{nbsp} |Name of the scope to which the configuration applies. - Scope name +Scope name |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_metrics_api_ScopingConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_metrics_api_ScopingConfig.adoc index a746c09d1bf..66647f2d924 100644 --- a/docs/src/main/asciidoc/config/io_helidon_metrics_api_ScopingConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_metrics_api_ScopingConfig.adoc @@ -43,15 +43,15 @@ Type: link:{javadoc-base-url}/io.helidon.metrics.api/io/helidon/metrics/api/Scop |key |type |default value |description |`default` |string |`application` |Default scope value to associate with meters that are registered without an explicit setting; no setting means meters - are assigned scope io.helidon.metrics.api.Meter.Scope.DEFAULT. +are assigned scope io.helidon.metrics.api.Meter.Scope.DEFAULT. - Default scope value +Default scope value |`scopes` |xref:{rootdir}/config/io_helidon_metrics_api_ScopeConfig.adoc[Map<string, ScopeConfig>] |{nbsp} |Settings for individual scopes. - Scope settings +Scope settings |`tag-name` |string |`scope` |Tag name for storing meter scope values in the underlying implementation meter registry. - Tag name for storing scope values +Tag name for storing scope values |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_microprofile_jwt.adoc b/docs/src/main/asciidoc/config/io_helidon_microprofile_jwt.adoc deleted file mode 100644 index f5b07663852..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_microprofile_jwt.adoc +++ /dev/null @@ -1,90 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2022, 2023 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. - -/////////////////////////////////////////////////////////////////////////////// - -// MANUALLY CREATED DOC - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.microprofile.jwt -:keywords: helidon, security, jwt, microprofile -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.microprofile.jwt.adoc -include::{rootdir}/includes/attributes.adoc[] - -= JWT Configuration - -// tag::config[] - -== Configuration options - - -.MicroProfile configuration options: -[cols="3,3,2,5a"] - -|=== -|key |type |default value |description - -|`mp.jwt.verify.publickey` |string |{nbsp} |The property allows the Public Verification Key text itself to be supplied as a string. -|`mp.jwt.verify.publickey.location` |string |{nbsp} |The property allows for an external or internal location of Public Verification Key to be specified. The value may be a relative path or a URL. -|`mp.jwt.verify.publickey.algorithm` |string |{nbsp} |The configuration property allows for specifying which Public Key Signature Algorithm is supported by the MP JWT endpoint. This property can be set to either `RS256` or `ES256`. Default value is `RS256`. Support for the other asymmetric signature algorithms such as `RS512`, `ES512` and others is optional. -|`mp.jwt.verify.issuer` |string |{nbsp} |Configuration key for expected issuer of incoming tokens. -|`mp.jwt.verify.audiences` |string |{nbsp} |Configuration key for expected audiences of incoming tokens. -|`mp.jwt.verify.token.age` |int |{nbsp} |Max number of seconds since token issue time. If this number of second accedes configured value, validation will fail. -|`mp.jwt.verify.clock.skew` |int |{nbsp} |Number of seconds for the clock skew during the token age verification and expiry. -|`mp.jwt.token.cookie` |string |{nbsp} |Cookie property name which is expected to contain a JWT token. -|`mp.jwt.token.header` |string |{nbsp} |Header name which is expected to contain a JWT token. -|`mp.jwt.decrypt.key.location` |string |{nbsp} |The property allows for an external or internal location of Private Decryption Key to be specified. The value may be a relative path or a URL. -|`mp.jwt.decrypt.key.algorithm` |string |{nbsp} |The configuration property allows for specifying which key management algorithm is supported by the MP JWT endpoint. Supported algorithms are either `RSA-OAEP` or `RSA-OAEP-256`. If no algorithm is set, both algorithms must be accepted. - -|=== - -.Helidon configuration options: -[cols="3,3,2,5a"] - -|=== -|key |type |default value |description - -|`optional` |boolean |`false` |If set to `true`, failure to authenticate will return `ABSTAIN` result instead of `FAILURE`. This is -an important distinction when more than one provider is used -|`authenticate` |boolean |`true` |Whether to attempt authentication -|`propagate`|boolean |`true` |Whether to attempt identity propagation/JWT creation -|`principal-type`|string |`USER` |Whether we authenticate a user or a service (other option is SERVICE) -|`atn-token` |string |{nbsp} |A group for configuring authentication of the request -|`atn-token.verify-signature`|boolean |`true` |Whether to verify signature in incoming JWT. If disabled, _ANY_ JWT will be accepted -|`atn-token.jwt-audience`|string |{nbsp} |Expected audience of the JWT. If not defined, any audience is accepted (and we may accept JWT not inteded for us) -|`atn-token.jwk.resource`|xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Configuration of the JWK to obtain key(s) to validate signatures of inbound token. The JWK should contain public keys. -|`atn-token.handler`|string |`Authorization` header with `bearer ` prefix |A handler configuration for inbound token - e.g. how to extract it -|`atn-token.handler.header`|string |{nbsp} |Name of a header the token is expected in -|`atn-token.handler.prefix`|string |{nbsp} |Prefix before the token value (optional) -|`atn-token.handler.regexp`|string |{nbsp} |Regular expression to obtain the token, first matching group is used (optional) -|`sign-token`|string |{nbsp} |A group for configuring outbound security -|`sign-token.jwk.resource`|xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Configuration of the JWK to use when generating tokens (follows the same rules as atn-token.jwk above). The JWK must contain private keys when using asymmetric ciphers. -|`sign-token.jwt-issuer`|string |{nbsp} |When we issue a new token, this is the issuer to be placed into it (validated by target service) -|`sign-token.outbound`|string |{nbsp} |A group for configuring outbound rules (based on transport, host and.or path) -|`sign-token.outbound.*.name`|string |{nbsp} |A short descriptive name for configured target service(s) -|`sign-token.outbound.*.transports`|string |any |An array of transports this outbound matches (e.g. https) -|`sign-token.outbound.*.hosts`|string |any |An array of hosts this outbound matches, may use * as a wild-card (e.g. *.oracle.com) -|`sign-token.outbound.*.paths`|string |any |An array of paths on the host this outbound matches, may use * as a wild-card (e.g. /some/path/*) -|`sign-token.outbound.*.outbound-token`|string |`Authorization` header with `bearer ` prefix |Configuration of outbound token handler (same as atn-token.handler) -|`sign-token.outbound.*.outbound-token.format`|string |{nbsp} |Java text format for generating the value of outbound token header (e.g. "bearer %1$s") -|`sign-token.outbound.*.jwk-kid`|string |{nbsp} |If this key is defined, we are generating a new token, otherwise we propagate existing. Defines the key id of a key definition in the JWK file to use for signing the outbound token -|`sign-token.outbound.*.jwt-kid`|string |{nbsp} |A key to use in the generated JWT - this is for the other service to locate the verification key in their JWK -|`sign-token.outbound.*.jwt-audience`|string |{nbsp} |Audience this key is generated for (e.g. http://www.example.org/api/myService) - validated by the other service -|`sign-token.outbound.*.jwt-not-before-seconds`|string |`5` |Makes this key valid this amount of seconds into the past. Allows a certain time-skew for the generated token to be valid before current time (e.g. when we expect a certain misalignment of clocks) -|`sign-token.outbound.*.jwt-validity-seconds`|string |1 day |Token validity in seconds -|=== - -// end::config[] diff --git a/docs/src/main/asciidoc/config/io_helidon_microprofile_jwt_auth_JwtAuthProvider.adoc b/docs/src/main/asciidoc/config/io_helidon_microprofile_jwt_auth_JwtAuthProvider.adoc new file mode 100644 index 00000000000..fe409f265d9 --- /dev/null +++ b/docs/src/main/asciidoc/config/io_helidon_microprofile_jwt_auth_JwtAuthProvider.adoc @@ -0,0 +1,90 @@ +/////////////////////////////////////////////////////////////////////////////// + + Copyright (c) 2024 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. + +/////////////////////////////////////////////////////////////////////////////// + +ifndef::rootdir[:rootdir: {docdir}/..] +:description: Configuration of io.helidon.microprofile.jwt.auth.JwtAuthProvider +:keywords: helidon, config, io.helidon.microprofile.jwt.auth.JwtAuthProvider +:basic-table-intro: The table below lists the configuration keys that configure io.helidon.microprofile.jwt.auth.JwtAuthProvider +include::{rootdir}/includes/attributes.adoc[] + += JwtAuthProvider (microprofile.jwt.auth) Configuration + +// tag::config[] + +MP-JWT Auth configuration is defined by the spec (options prefixed with `mp.jwt.`), and we add a few configuration options for the security provider (options prefixed with `security.providers.mp-jwt-auth.`) + + +Type: link:{javadoc-base-url}/io.helidon.microprofile.jwt.auth/io/helidon/microprofile/jwt/auth/JwtAuthProvider.html[io.helidon.microprofile.jwt.auth.JwtAuthProvider] + + + + +== Configuration options + + + +.Optional configuration options +[cols="3,3a,2,5a"] + +|=== +|key |type |default value |description + +|`mp.jwt.decrypt.key.algorithm` |string (RSA-OAEP, RSA-OAEP-256) |{nbsp} |Expected key management algorithm supported by the MP JWT endpoint. +Supported algorithms are either `RSA-OAEP` or `RSA-OAEP-256`. +If no algorithm is set, both algorithms must be accepted. + +Allowed values: + +- `RSA-OAEP`: RSA-OAEP Algorithm +- `RSA-OAEP-256`: RSA-OAEP-256 Algorithm + +|`mp.jwt.decrypt.key.location` |string |{nbsp} |Private key for decryption of encrypted claims. +The value may be a relative path or a URL. +|`mp.jwt.token.cookie` |string |`Bearer` |Specific cookie property name where we should search for JWT property. +|`mp.jwt.token.header` |string |`Authorization` |Name of the header expected to contain the token. +|`mp.jwt.verify.audiences` |string[] |{nbsp} |Expected audiences of incoming tokens. +|`mp.jwt.verify.clock.skew` |int |`5` |Clock skew to be accounted for in token expiration and max age validations in seconds. +|`mp.jwt.verify.issuer` |string |{nbsp} |Expected issuer in incoming requests. +|`mp.jwt.verify.publickey` |string |{nbsp} |String representation of the public key. +|`mp.jwt.verify.publickey.location` |string |{nbsp} |Path to public key. +The value may be a relative path or a URL. +|`mp.jwt.verify.token.age` |int |{nbsp} |Maximal expected token age in seconds. If this value is set, `iat` claim needs to be present in the JWT. +|`security.providers.mp-jwt-auth.allow-impersonation` |boolean |`false` |Whether to allow impersonation by explicitly overriding +username from outbound requests using io.helidon.security.EndpointConfig.PROPERTY_OUTBOUND_ID +property. +By default this is not allowed and identity can only be propagated. +|`security.providers.mp-jwt-auth.atn-token.default-key-id` |string |{nbsp} |Default JWT key ID which should be used. +|`security.providers.mp-jwt-auth.atn-token.handler` |xref:{rootdir}/config/io_helidon_security_util_TokenHandler.adoc[TokenHandler] |{nbsp} |Token handler to extract username from request. +Uses `Authorization` header with `bearer ` prefix by default. +|`security.providers.mp-jwt-auth.atn-token.jwk.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |JWK resource for authenticating the request +|`security.providers.mp-jwt-auth.atn-token.jwt-audience` |string |{nbsp} |Audience expected in inbound JWTs. +|`security.providers.mp-jwt-auth.atn-token.verify-key` |string |{nbsp} |Path to public key. +The value may be a relative path or a URL. +|`security.providers.mp-jwt-auth.authenticate` |boolean |`true` |Whether to authenticate requests. +|`security.providers.mp-jwt-auth.load-on-startup` |boolean |`false` |Whether to load JWK verification keys on server startup +Default value is `false`. +|`security.providers.mp-jwt-auth.optional` |boolean |`false` |Whether authentication is required. +By default, request will fail if the username cannot be extracted. +If set to false, request will process and this provider will abstain. +|`security.providers.mp-jwt-auth.principal-type` |SubjectType (USER, SERVICE) |`USER` |Principal type this provider extracts (and also propagates). +|`security.providers.mp-jwt-auth.propagate` |boolean |`true` |Whether to propagate identity. +|`security.providers.mp-jwt-auth.sign-token` |xref:{rootdir}/config/io_helidon_security_providers_common_OutboundConfig.adoc[OutboundConfig] |{nbsp} |Configuration of outbound rules. + +|=== + +// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_microprofile_openapi_MpOpenApiManagerConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_microprofile_openapi_MpOpenApiManagerConfig.adoc index 23d30831f44..fdc573009bf 100644 --- a/docs/src/main/asciidoc/config/io_helidon_microprofile_openapi_MpOpenApiManagerConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_microprofile_openapi_MpOpenApiManagerConfig.adoc @@ -43,9 +43,9 @@ Type: link:{javadoc-base-url}/io.helidon.microprofile.openapi/io/helidon/micropr |key |type |default value |description |`mp.openapi.extensions.helidon.use-jaxrs-semantics` |boolean |{nbsp} |If `true` and the `jakarta.ws.rs.core.Application` class returns a non-empty set, endpoints defined by - other resources are not included in the OpenAPI document. +other resources are not included in the OpenAPI document. - `true` if enabled, `false` otherwise +`true` if enabled, `false` otherwise |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_openapi_OpenApiFeature.adoc b/docs/src/main/asciidoc/config/io_helidon_openapi_OpenApiFeature.adoc index 61f46f41ac7..275d8a67a84 100644 --- a/docs/src/main/asciidoc/config/io_helidon_openapi_OpenApiFeature.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_openapi_OpenApiFeature.adoc @@ -50,36 +50,36 @@ This type provides the following service implementations: |`cors` |xref:{rootdir}/config/io_helidon_cors_CrossOriginConfig.adoc[CrossOriginConfig] |{nbsp} |CORS config. - CORS config +CORS config |`enabled` |boolean |`true` |Sets whether the feature should be enabled. - `true` if enabled, `false` otherwise +`true` if enabled, `false` otherwise |`manager` |io.helidon.openapi.OpenApiManager (service provider interface) |{nbsp} |OpenAPI manager. - The OpenAPI manager +The OpenAPI manager |`permit-all` |boolean |`true` |Whether to allow anybody to access the endpoint. - Whether to permit access to metrics endpoint to anybody, defaults to `true` - See roles() +Whether to permit access to metrics endpoint to anybody, defaults to `true` +See roles() |`roles` |string[] |`openapi` |Hints for role names the user is expected to be in. - List of hints +List of hints |`services` |io.helidon.openapi.OpenApiService[] (service provider interface) |{nbsp} |OpenAPI services. - The OpenAPI services +The OpenAPI services |`sockets` |string[] |{nbsp} |List of sockets to register this feature on. If empty, it would get registered on all sockets. - Socket names to register on, defaults to empty (all available sockets) +Socket names to register on, defaults to empty (all available sockets) |`static-file` |string |{nbsp} |Path of the static OpenAPI document file. Default types are `json`, `yaml`, and `yml`. - Location of the static OpenAPI document file +Location of the static OpenAPI document file |`web-context` |string |`/openapi` |Web context path for the OpenAPI endpoint. - WebContext to use +WebContext to use |`weight` |double |`90.0` |Weight of the OpenAPI feature. This is quite low, to be registered after routing. - io.helidon.openapi.OpenApiFeature.WEIGHT. +io.helidon.openapi.OpenApiFeature.WEIGHT. - Weight of the feature +Weight of the feature |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_scheduling_Cron.adoc b/docs/src/main/asciidoc/config/io_helidon_scheduling_Cron.adoc index afbb32ab850..f69f9df6925 100644 --- a/docs/src/main/asciidoc/config/io_helidon_scheduling_Cron.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_scheduling_Cron.adoc @@ -41,7 +41,7 @@ Type: link:{javadoc-base-url}/io.helidon.scheduling/io/helidon/scheduling/Cron.h |`expression` |string |{nbsp} |Cron expression for specifying period of execution. - Examples: +*Examples:* - `0/2 * * * * ? *` - Every 2 seconds - `0 45 9 ? * *` - Every day at 9:45 @@ -60,9 +60,9 @@ Cron expression |key |type |default value |description |`concurrent` |boolean |`true` |Allow concurrent execution if previous task didn't finish before next execution. - Default value is `true`. +Default value is `true`. - True for allow concurrent execution. +True for allow concurrent execution. |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_scheduling_FixedRate.adoc b/docs/src/main/asciidoc/config/io_helidon_scheduling_FixedRate.adoc index 301fd9df2f1..d494d3bcb7e 100644 --- a/docs/src/main/asciidoc/config/io_helidon_scheduling_FixedRate.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_scheduling_FixedRate.adoc @@ -40,9 +40,9 @@ Type: link:{javadoc-base-url}/io.helidon.scheduling/io/helidon/scheduling/FixedR |key |type |default value |description |`delay` |long |{nbsp} |Fixed rate delay between each invocation. Time unit is by default java.util.concurrent.TimeUnit.SECONDS, - can be specified with io.helidon.scheduling.FixedRateConfig.Builder.timeUnit(java.util.concurrent.TimeUnit). +can be specified with io.helidon.scheduling.FixedRateConfig.Builder.timeUnit(java.util.concurrent.TimeUnit). - Delay between each invocation +Delay between each invocation |=== @@ -54,22 +54,28 @@ Type: link:{javadoc-base-url}/io.helidon.scheduling/io/helidon/scheduling/FixedR |=== |key |type |default value |description -|`delay-type` |DelayType |`DelayType.SINCE_PREVIOUS_START` |Configure whether the delay between the invocations should be calculated from the time when previous task started or ended. - Delay type is by default FixedRate.DelayType.SINCE_PREVIOUS_START. +|`delay-type` |DelayType (SINCE_PREVIOUS_START, SINCE_PREVIOUS_END) |`DelayType.SINCE_PREVIOUS_START` |Configure whether the delay between the invocations should be calculated from the time when previous task started or ended. +Delay type is by default FixedRate.DelayType.SINCE_PREVIOUS_START. + +Delay type + +Allowed values: + +- `SINCE_PREVIOUS_START`: Next invocation delay is measured from the previous invocation task start. +- `SINCE_PREVIOUS_END`: Next invocation delay is measured from the previous invocation task end. - Delay type |`initial-delay` |long |`0` |Initial delay of the first invocation. Time unit is by default java.util.concurrent.TimeUnit.SECONDS, - can be specified with - io.helidon.scheduling.FixedRateConfig.Builder.timeUnit(java.util.concurrent.TimeUnit) timeUnit(). +can be specified with +io.helidon.scheduling.FixedRateConfig.Builder.timeUnit(java.util.concurrent.TimeUnit) timeUnit(). - Initial delay value -|`time-unit` |TimeUnit |`TimeUnit.TimeUnit.SECONDS` |java.util.concurrent.TimeUnit TimeUnit used for interpretation of values provided with - io.helidon.scheduling.FixedRateConfig.Builder.delay(long) - and io.helidon.scheduling.FixedRateConfig.Builder.initialDelay(long). +Initial delay value +|`time-unit` |TimeUnit (NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS) |`TimeUnit.TimeUnit.SECONDS` |java.util.concurrent.TimeUnit TimeUnit used for interpretation of values provided with +io.helidon.scheduling.FixedRateConfig.Builder.delay(long) +and io.helidon.scheduling.FixedRateConfig.Builder.initialDelay(long). - Time unit for interpreting values - in io.helidon.scheduling.FixedRateConfig.Builder.delay(long) - and io.helidon.scheduling.FixedRateConfig.Builder.initialDelay(long) +Time unit for interpreting values + in io.helidon.scheduling.FixedRateConfig.Builder.delay(long) + and io.helidon.scheduling.FixedRateConfig.Builder.initialDelay(long) |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_security_Security.adoc b/docs/src/main/asciidoc/config/io_helidon_security_Security.adoc index 7aa7f794246..dc0be6f755b 100644 --- a/docs/src/main/asciidoc/config/io_helidon_security_Security.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_security_Security.adoc @@ -48,6 +48,7 @@ This is a standalone configuration type, prefix from configuration root: `securi Such as: - xref:{rootdir}/config/io_helidon_security_providers_idcs_mapper_IdcsRoleMapperProvider.adoc[idcs-role-mapper (IdcsRoleMapperProvider)] + - xref:{rootdir}/config/io_helidon_security_providers_config_vault_ConfigVaultProvider.adoc[config-vault (ConfigVaultProvider)] - xref:{rootdir}/config/io_helidon_security_providers_jwt_JwtProvider.adoc[jwt (JwtProvider)] - xref:{rootdir}/config/io_helidon_security_providers_httpauth_HttpBasicAuthProvider.adoc[http-basic-auth (HttpBasicAuthProvider)] - xref:{rootdir}/config/io_helidon_security_providers_idcs_mapper_IdcsMtRoleMapperProvider.adoc[idcs-role-mapper (IdcsMtRoleMapperProvider)] @@ -58,7 +59,7 @@ Such as: - xref:{rootdir}/config/io_helidon_security_providers_abac_AbacProvider.adoc[abac (AbacProvider)] |{nbsp} |Add a provider, works as addProvider(io.helidon.security.spi.SecurityProvider, String), where the name is set - to `Class#getSimpleName()`. +to `Class#getSimpleName()`. |=== @@ -73,14 +74,29 @@ Such as: |`default-authentication-provider` |string (service provider interface) |{nbsp} |ID of the default authentication provider |`default-authorization-provider` |string |{nbsp} |ID of the default authorization provider |`enabled` |boolean |`true` |Security can be disabled using configuration, or explicitly. - By default, security instance is enabled. - Disabled security instance will not perform any checks and allow - all requests. +By default, security instance is enabled. +Disabled security instance will not perform any checks and allow +all requests. |`environment.server-time` |xref:{rootdir}/config/io_helidon_security_SecurityTime.adoc[SecurityTime] |{nbsp} |Server time to use when evaluating security policies that depend on time. |`provider-policy.class-name` |Class |{nbsp} |Provider selection policy class name, only used when type is set to CLASS |`provider-policy.type` |ProviderSelectionPolicyType (FIRST, COMPOSITE, CLASS) |`FIRST` |Type of the policy. + +Allowed values: + +- `FIRST`: Choose first provider from the list by default. +Choose provider with the name defined when explicit provider requested. +- `COMPOSITE`: Can compose multiple providers together to form a single +logical provider. +- `CLASS`: Explicit class for a custom ProviderSelectionPolicyType. + |`secrets` |Map<string, string> (documented for specific cases) |{nbsp} |Configured secrets -|`secrets.*.config` |io.helidon.security.SecretsProviderConfig (service provider interface) |{nbsp} |Configuration specific to the secret provider +|`secrets.*.config` |io.helidon.security.SecretsProviderConfig (service provider interface) + +Such as: + + - xref:{rootdir}/config/io_helidon_security_providers_config_vault_ConfigVaultProvider_SecretConfig.adoc[SecretConfig] + + |{nbsp} |Configuration specific to the secret provider |`secrets.*.name` |string |{nbsp} |Name of the secret, used for lookup |`secrets.*.provider` |string |{nbsp} |Name of the secret provider |`tracing.enabled` |boolean |`true` |Whether or not tracing should be enabled. If set to false, security tracer will be a no-op tracer. diff --git a/docs/src/main/asciidoc/config/io_helidon_security_SecurityTime.adoc b/docs/src/main/asciidoc/config/io_helidon_security_SecurityTime.adoc index e698c1b2fab..a5b7eeab695 100644 --- a/docs/src/main/asciidoc/config/io_helidon_security_SecurityTime.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_security_SecurityTime.adoc @@ -51,8 +51,8 @@ Type: link:{javadoc-base-url}/io.helidon.security/io/helidon/security/SecurityTi |`shift-by-seconds` |long |`0` |Configure a time-shift in seconds, to move the current time to past or future. |`time-zone` |ZoneId |{nbsp} |Override current time zone. The time will represent the SAME instant, in an explicit timezone. - If we are in a UTC time zone and you set the timezone to "Europe/Prague", the time will be shifted by the offset - of Prague (e.g. if it is noon right now in UTC, you would get 14:00). +If we are in a UTC time zone and you set the timezone to "Europe/Prague", the time will be shifted by the offset +of Prague (e.g. if it is noon right now in UTC, you would get 14:00). |`year` |long |{nbsp} |Set an explicit value for one of the time fields (such as ChronoField.YEAR). |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_common_EvictableCache.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_common_EvictableCache.adoc index e58103fa272..bc02a878aed 100644 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_common_EvictableCache.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_security_providers_common_EvictableCache.adoc @@ -43,14 +43,14 @@ Type: link:{javadoc-base-url}/io.helidon.security.providers.common/io/helidon/se |key |type |default value |description |`cache-enabled` |boolean |`true` |If the cacheEnabled is set to false, no caching will be done. - Otherwise (default behavior) evictable caching will be used. +Otherwise (default behavior) evictable caching will be used. |`cache-evict-delay-millis` |long |`60000` |Delay from the creation of the cache to first eviction |`cache-evict-period-millis` |long |`300000` |How often to evict records |`cache-overall-timeout-millis` |long |`3600000` |Configure record timeout since its creation. |`cache-timeout-millis` |long |`3600000` |Configure record timeout since last access. |`evictor-class` |Class |{nbsp} |Configure evictor to check if a record is still valid. - This should be a fast way to check, as it is happening in a ConcurrentHashMap.forEachKey(long, Consumer). - This is also called during all get and remove operations to only return valid records. +This should be a fast way to check, as it is happening in a ConcurrentHashMap.forEachKey(long, Consumer). +This is also called during all get and remove operations to only return valid records. |`max-size` |long |`100000` |Configure maximal cache size. |`parallelism-threshold` |long |`10000` |Configure parallelism threshold. diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_common_OutboundTarget.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_common_OutboundTarget.adoc index b89ca777630..3c9e2cec3b0 100644 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_common_OutboundTarget.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_security_providers_common_OutboundTarget.adoc @@ -1,6 +1,6 @@ /////////////////////////////////////////////////////////////////////////////// - Copyright (c) 2023 Oracle and/or its affiliates. + Copyright (c) 2023, 2024 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. @@ -53,31 +53,31 @@ Type: link:{javadoc-base-url}/io.helidon.security.providers.common/io/helidon/se |`hosts` |string[] |{nbsp} |Add supported host for this target. May be called more than once to add more hosts. - Valid examples: +Valid examples: - localhost - + - www.google.com - + - 127.0.0.1 - + - *.oracle.com - + - 192.169.*.* - + - *.google.* |`methods` |string[] |{nbsp} |Add supported method for this target. May be called more than once to add more methods. - The method is tested as is ignoring case against the used method. +The method is tested as is ignoring case against the used method. |`paths` |string[] |{nbsp} |Add supported paths for this target. May be called more than once to add more paths. - The path is tested as is against called path, and also tested as a regular expression. +The path is tested as is against called path, and also tested as a regular expression. |`transport` |string[] |{nbsp} |Add supported transports for this target. May be called more than once to add more transports. - Valid examples: +Valid examples: - http - + - https There is no wildcard support diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_config_vault_ConfigVaultProvider.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_config_vault_ConfigVaultProvider.adoc new file mode 100644 index 00000000000..02fe4a1679e --- /dev/null +++ b/docs/src/main/asciidoc/config/io_helidon_security_providers_config_vault_ConfigVaultProvider.adoc @@ -0,0 +1,64 @@ +/////////////////////////////////////////////////////////////////////////////// + + Copyright (c) 2024 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. + +/////////////////////////////////////////////////////////////////////////////// + +ifndef::rootdir[:rootdir: {docdir}/..] +:description: Configuration of io.helidon.security.providers.config.vault.ConfigVaultProvider +:keywords: helidon, config, io.helidon.security.providers.config.vault.ConfigVaultProvider +:basic-table-intro: The table below lists the configuration keys that configure io.helidon.security.providers.config.vault.ConfigVaultProvider +include::{rootdir}/includes/attributes.adoc[] + += ConfigVaultProvider (security.providers.config.vault) Configuration + +// tag::config[] + +Secrets and Encryption provider using just configuration + + +Type: link:{javadoc-base-url}/io.helidon.security.providers.config.vault/io/helidon/security/providers/config/vault/ConfigVaultProvider.html[io.helidon.security.providers.config.vault.ConfigVaultProvider] + + +[source,text] +.Config key +---- +config-vault +---- + + +This type provides the following service implementations: + +- `io.helidon.security.spi.SecurityProvider` +- `io.helidon.security.spi.SecretsProvider` +- `io.helidon.security.spi.EncryptionProvider` + + +== Configuration options + +.Required configuration options +[cols="3,3a,2,5a"] +|=== +|key |type |default value |description + +|`master-password` |string |{nbsp} |Configure master password used for encryption/decryption. +If master password cannot be obtained from any source (this method, configuration, system property, +environment variable), encryption and decryption will not be supported. + +|=== + + + +// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_servicecommon_RestServiceSettings_Builder.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_config_vault_ConfigVaultProvider_SecretConfig.adoc similarity index 52% rename from docs/src/main/asciidoc/config/io_helidon_webserver_servicecommon_RestServiceSettings_Builder.adoc rename to docs/src/main/asciidoc/config/io_helidon_security_providers_config_vault_ConfigVaultProvider_SecretConfig.adoc index 32e941a325d..604012e420c 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_servicecommon_RestServiceSettings_Builder.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_security_providers_config_vault_ConfigVaultProvider_SecretConfig.adoc @@ -17,21 +17,27 @@ /////////////////////////////////////////////////////////////////////////////// ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.servicecommon.RestServiceSettings.Builder -:keywords: helidon, config, io.helidon.webserver.servicecommon.RestServiceSettings.Builder -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.servicecommon.RestServiceSettings.Builder +:description: Configuration of io.helidon.security.providers.config.vault.ConfigVaultProvider.SecretConfig +:keywords: helidon, config, io.helidon.security.providers.config.vault.ConfigVaultProvider.SecretConfig +:basic-table-intro: The table below lists the configuration keys that configure io.helidon.security.providers.config.vault.ConfigVaultProvider.SecretConfig include::{rootdir}/includes/attributes.adoc[] -= Builder (webserver.servicecommon.RestServiceSettings) Configuration += SecretConfig (security.providers.config.vault.ConfigVaultProvider) Configuration // tag::config[] +Provider of secrets defined in configuration itself -Type: link:{javadoc-base-url}/io.helidon.webserver.servicecommon.RestServiceSettings/io/helidon/webserver/servicecommon/RestServiceSettings/Builder.html[io.helidon.webserver.servicecommon.RestServiceSettings.Builder] +Type: link:{javadoc-base-url}/io.helidon.security.providers.config.vault.ConfigVaultProvider/io/helidon/security/providers/config/vault/ConfigVaultProvider/SecretConfig.html[io.helidon.security.providers.config.vault.ConfigVaultProvider.SecretConfig] +This type provides the following service implementations: + +- `io.helidon.security.SecretsProviderConfig` + + == Configuration options @@ -42,10 +48,7 @@ Type: link:{javadoc-base-url}/io.helidon.webserver.servicecommon.RestServiceSett |=== |key |type |default value |description -|`cors` |xref:{rootdir}/config/io_helidon_cors_CrossOriginConfig.adoc[Map<string, CrossOriginConfig>] |{nbsp} |Sets the cross-origin config builder for use in establishing CORS support for the service endpoints. -|`enabled` |boolean |`true` |Is this service enabled or not. -|`routing` |string |{nbsp} |Sets the routing name to use for setting up the service's endpoint. -|`web-context` |string |{nbsp} |Sets the web context to use for the service's endpoint. +|`value` |ConfiguredOption |{nbsp} |Value of the secret, can be a reference to another configuration key, such as ${app.secret} |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_google_login_GoogleTokenProvider.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_google_login_GoogleTokenProvider.adoc index d9b8791fab3..245347d4c51 100644 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_google_login_GoogleTokenProvider.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_security_providers_google_login_GoogleTokenProvider.adoc @@ -57,9 +57,9 @@ This type provides the following service implementations: |`client-id` |string |{nbsp} |Google application client id, to validate that the token was generated by Google for us. |`optional` |boolean |`false` |If set to true, this provider will return io.helidon.security.SecurityResponse.SecurityStatus.ABSTAIN instead - of failing in case of invalid request. +of failing in case of invalid request. |`outbound` |xref:{rootdir}/config/io_helidon_security_providers_common_OutboundConfig.adoc[OutboundConfig] |{nbsp} |Outbound configuration - a set of outbound targets that - will have the token propagated. +will have the token propagated. |`proxy-host` |string |{nbsp} |Set proxy host when talking to Google. |`proxy-port` |int |`80` |Set proxy port when talking to Google. |`realm` |string |`helidon` |Set the authentication realm to build challenge, defaults to "helidon". diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_header_HeaderAtnProvider.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_header_HeaderAtnProvider.adoc index cf267481c23..9ab2b5c1863 100644 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_header_HeaderAtnProvider.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_security_providers_header_HeaderAtnProvider.adoc @@ -58,11 +58,11 @@ This type provides the following service implementations: |`atn-token` |xref:{rootdir}/config/io_helidon_security_util_TokenHandler.adoc[TokenHandler] |{nbsp} |Token handler to extract username from request. |`authenticate` |boolean |`true` |Whether to authenticate requests. |`optional` |boolean |`false` |Whether authentication is required. - By default, request will fail if the username cannot be extracted. - If set to false, request will process and this provider will abstain. +By default, request will fail if the username cannot be extracted. +If set to false, request will process and this provider will abstain. |`outbound` |xref:{rootdir}/config/io_helidon_security_providers_common_OutboundTarget.adoc[OutboundTarget[]] |{nbsp} |Configure outbound target for identity propagation. |`outbound-token` |xref:{rootdir}/config/io_helidon_security_util_TokenHandler.adoc[TokenHandler] |{nbsp} |Token handler to create outbound headers to propagate identity. - If not defined, atnTokenHandler will be used. +If not defined, atnTokenHandler will be used. |`principal-type` |SubjectType (USER, SERVICE) |`USER` |Principal type this provider extracts (and also propagates). |`propagate` |boolean |`false` |Whether to propagate identity. diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_httpauth_HttpBasicAuthProvider.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_httpauth_HttpBasicAuthProvider.adoc index 9ba61b0ab0b..0e902bbef34 100644 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_httpauth_HttpBasicAuthProvider.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_security_providers_httpauth_HttpBasicAuthProvider.adoc @@ -56,13 +56,13 @@ This type provides the following service implementations: |key |type |default value |description |`optional` |boolean |`false` |Whether authentication is required. - By default, request will fail if the authentication cannot be verified. - If set to false, request will process and this provider will abstain. +By default, request will fail if the authentication cannot be verified. +If set to false, request will process and this provider will abstain. |`outbound` |xref:{rootdir}/config/io_helidon_security_providers_common_OutboundTarget.adoc[OutboundTarget[]] |{nbsp} |Add a new outbound target to configure identity propagation or explicit username/password. |`principal-type` |SubjectType (USER, SERVICE) |`USER` |Principal type this provider extracts (and also propagates). |`realm` |string |`helidon` |Set the realm to use when challenging users. |`users` |xref:{rootdir}/config/io_helidon_security_providers_httpauth_ConfigUserStore_ConfigUser.adoc[ConfigUser[]] |{nbsp} |Set user store to validate users. - Removes any other stores added through addUserStore(SecureUserStore). +Removes any other stores added through addUserStore(SecureUserStore). |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_httpauth_HttpDigestAuthProvider.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_httpauth_HttpDigestAuthProvider.adoc index a548cdd044f..12711830dc1 100644 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_httpauth_HttpDigestAuthProvider.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_security_providers_httpauth_HttpDigestAuthProvider.adoc @@ -1,6 +1,6 @@ /////////////////////////////////////////////////////////////////////////////// - Copyright (c) 2023 Oracle and/or its affiliates. + Copyright (c) 2023, 2024 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. @@ -56,18 +56,32 @@ This type provides the following service implementations: |key |type |default value |description |`algorithm` |Algorithm (MD5) |`MD5` |Digest algorithm to use. + +Allowed values: + +- `MD5`: MD5 algorithm. + |`nonce-timeout-millis` |long |`86400000` |How long will the nonce value be valid. When timed-out, browser will re-request username/password. |`optional` |boolean |`false` |Whether authentication is required. - By default, request will fail if the authentication cannot be verified. - If set to false, request will process and this provider will abstain. +By default, request will fail if the authentication cannot be verified. +If set to false, request will process and this provider will abstain. |`principal-type` |SubjectType (USER, SERVICE) |`USER` |Principal type this provider extracts (and also propagates). |`qop` |Qop (NONE, AUTH) |`NONE` |Only `AUTH` supported. If left empty, uses the legacy approach (older RFC version). `AUTH-INT` is not supported. + +Allowed values: + +- `NONE`: Legacy approach - used internally to parse headers. Do not use this option when +building provider. If you want to support only legacy RFC, please use +HttpDigestAuthProvider.Builder.noDigestQop(). +Only AUTH is supported, as auth-int requires access to message body. +- `AUTH`: QOP "auth" - stands for "authentication". + |`realm` |string |`Helidon` |Set the realm to use when challenging users. |`server-secret` |string |{nbsp} |The nonce is encrypted using this secret - to make sure the nonce we get back was generated by us and to - make sure we can safely time-out nonce values. - This secret must be the same for all service instances (or all services that want to share the same authentication). - Defaults to a random password - e.g. if deployed to multiple servers, the authentication WILL NOT WORK. You MUST - provide your own password to work in a distributed environment with non-sticky load balancing. +make sure we can safely time-out nonce values. +This secret must be the same for all service instances (or all services that want to share the same authentication). +Defaults to a random password - e.g. if deployed to multiple servers, the authentication WILL NOT WORK. You MUST +provide your own password to work in a distributed environment with non-sticky load balancing. |`users` |xref:{rootdir}/config/io_helidon_security_providers_httpauth_ConfigUserStore_ConfigUser.adoc[ConfigUser[]] |{nbsp} |Set user store to obtain passwords and roles based on logins. |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_httpsign_HttpSignProvider.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_httpsign_HttpSignProvider.adoc index 4135b525654..ebbab063bf8 100644 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_httpsign_HttpSignProvider.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_security_providers_httpsign_HttpSignProvider.adoc @@ -56,75 +56,91 @@ This type provides the following service implementations: |`backward-compatible-eol` |boolean |`false` |Enable support for Helidon versions before 3.0.0 (exclusive). - Until version 3.0.0 (exclusive) there was a trailing end of line added to the signed - data. - To be able to communicate cross versions, we must configure this when talking to older versions of Helidon. - Default value is `false`. In Helidon 2.x, this switch exists as well and the default is `true`, to - allow communication between versions as needed. +Until version 3.0.0 (exclusive) there was a trailing end of line added to the signed +data. +To be able to communicate cross versions, we must configure this when talking to older versions of Helidon. +Default value is `false`. In Helidon 2.x, this switch exists as well and the default is `true`, to +allow communication between versions as needed. |`headers` |HttpSignHeader[] (SIGNATURE, AUTHORIZATION, CUSTOM) |{nbsp} |Add a header that is validated on inbound requests. Provider may support more than - one header to validate. +one header to validate. + +Allowed values: + +- `SIGNATURE`: Creates (or validates) a "Signature" header. +- `AUTHORIZATION`: Creates (or validates) an "Authorization" header, that contains "Signature" as the +beginning of its content (the rest of the header is the same as for SIGNATURE. +- `CUSTOM`: Custom provided using a io.helidon.security.util.TokenHandler. + |`inbound.keys` |xref:{rootdir}/config/io_helidon_security_providers_httpsign_InboundClientDefinition.adoc[InboundClientDefinition[]] |{nbsp} |Add inbound configuration. This is used to validate signature and authenticate the - party. - - The same can be done through configuration: -

      - {
      -  name = "http-signatures"
      -  class = "HttpSignProvider"
      -  http-signatures {
      -      inbound {
      -          # This configures the InboundClientDefinition
      -          keys: [
      -          {
      -              key-id = "service1"
      -              hmac.secret = "${CLEAR=password}"
      -          }]
      -      }
      -  }
      +party.
      +
      +The same can be done through configuration:
      +
      +----
      +
      +{
      + name = "http-signatures"
      + class = "HttpSignProvider"
      + http-signatures {
      +     inbound {
      +         # This configures the InboundClientDefinition
      +         keys: [
      +         {
      +             key-id = "service1"
      +             hmac.secret = "${CLEAR=password}"
      +         }]
      +     }
        }
      - 
      +} + +---- + |`optional` |boolean |`true` |Set whether the signature is optional. If set to true (default), this provider will - SecurityResponse.SecurityStatus.ABSTAIN from this request if signature is not - present. If set to false, this provider will SecurityResponse.SecurityStatus.FAILURE fail - if signature is not present. +SecurityResponse.SecurityStatus.ABSTAIN from this request if signature is not +present. If set to false, this provider will SecurityResponse.SecurityStatus.FAILURE fail +if signature is not present. |`outbound` |xref:{rootdir}/config/io_helidon_security_providers_common_OutboundConfig.adoc[OutboundConfig] |{nbsp} |Add outbound targets to this builder. - The targets are used to chose what to do for outbound communication. - The targets should have OutboundTargetDefinition attached through - OutboundTarget.Builder.customObject(Class, Object) to tell us how to sign - the request. - - The same can be done through configuration: -
      - {
      -  name = "http-signatures"
      -  class = "HttpSignProvider"
      -  http-signatures {
      -      targets: [
      -      {
      -          name = "service2"
      -          hosts = ["localhost"]
      -          paths = ["/service2/.*"]
      -
      -          # This configures the OutboundTargetDefinition
      -          signature {
      -              key-id = "service1"
      -              hmac.secret = "${CLEAR=password}"
      -          }
      -      }]
      -  }
      +The targets are used to chose what to do for outbound communication.
      +The targets should have OutboundTargetDefinition attached through
      +OutboundTarget.Builder.customObject(Class, Object) to tell us how to sign
      +the request.
      +
      +The same can be done through configuration:
      +
      +----
      +
      +{
      + name = "http-signatures"
      + class = "HttpSignProvider"
      + http-signatures {
      +     targets: [
      +     {
      +         name = "service2"
      +         hosts = ["localhost"]
      +         paths = ["/service2/.*"]
      +
      +         # This configures the OutboundTargetDefinition
      +         signature {
      +             key-id = "service1"
      +             hmac.secret = "${CLEAR=password}"
      +         }
      +     }]
        }
      - 
      +} + +---- + |`realm` |string |`helidon` |Realm to use for challenging inbound requests that do not have "Authorization" header - in case header is HttpSignHeader.AUTHORIZATION and singatures are not optional. +in case header is HttpSignHeader.AUTHORIZATION and singatures are not optional. |`sign-headers` |xref:{rootdir}/config/io_helidon_security_providers_httpsign_SignedHeadersConfig_HeadersConfig.adoc[HeadersConfig[]] |{nbsp} |Override the default inbound required headers (e.g. headers that MUST be signed and - headers that MUST be signed IF present). +headers that MUST be signed IF present). - Defaults: +Defaults: - get, head, delete methods: date, (request-target), host are mandatory; authorization if present (unless we are - creating/validating the HttpSignHeader.AUTHORIZATION ourselves +creating/validating the HttpSignHeader.AUTHORIZATION ourselves - put, post: same as above, with addition of: content-length, content-type and digest if present - + - for other methods: date, (request-target) Note that this provider DOES NOT validate the "Digest" HTTP header, only the signature. diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_httpsign_InboundClientDefinition.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_httpsign_InboundClientDefinition.adoc index 9f134d63f49..43c503610e3 100644 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_httpsign_InboundClientDefinition.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_security_providers_httpsign_InboundClientDefinition.adoc @@ -43,14 +43,14 @@ Type: link:{javadoc-base-url}/io.helidon.security.providers.httpsign/io/helidon/ |key |type |default value |description |`algorithm` |string |{nbsp} |Algorithm of signature used by this client. - Currently supported: +Currently supported: - rsa-sha256 - asymmetric based on public/private keys - hmac-sha256 - symmetric based on a shared secret |`hmac.secret` |string |{nbsp} |Helper method to configure a password-like secret (instead of byte based hmacSecret(byte[]). - The password is transformed to bytes with StandardCharsets.UTF_8 charset. +The password is transformed to bytes with StandardCharsets.UTF_8 charset. |`key-id` |string |{nbsp} |The key id of this client to map to this signature validation configuration. |`principal-name` |string |{nbsp} |The principal name of the client, defaults to keyId if not configured. |`principal-type` |SubjectType (USER, SERVICE) |`SERVICE` |The type of principal we have authenticated (either user or service, defaults to service). diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_idcs_mapper_IdcsMtRoleMapperProvider.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_idcs_mapper_IdcsMtRoleMapperProvider.adoc index 3edcf211006..af72a410d6c 100644 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_idcs_mapper_IdcsMtRoleMapperProvider.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_security_providers_idcs_mapper_IdcsMtRoleMapperProvider.adoc @@ -57,19 +57,19 @@ This type provides the following service implementations: |`cache-config` |xref:{rootdir}/config/io_helidon_security_providers_common_EvictableCache.adoc[EvictableCache] |{nbsp} |Use explicit io.helidon.security.providers.common.EvictableCache for role caching. |`default-idcs-subject-type` |string |`user` |Configure subject type to use when requesting roles from IDCS. - Can be either IDCS_SUBJECT_TYPE_USER or IDCS_SUBJECT_TYPE_CLIENT. - Defaults to IDCS_SUBJECT_TYPE_USER. +Can be either IDCS_SUBJECT_TYPE_USER or IDCS_SUBJECT_TYPE_CLIENT. +Defaults to IDCS_SUBJECT_TYPE_USER. |`idcs-app-name-handler` |xref:{rootdir}/config/io_helidon_security_util_TokenHandler.adoc[TokenHandler] |{nbsp} |Configure token handler for IDCS Application name. - By default the header IdcsMtRoleMapperProvider.IDCS_APP_HEADER is used. +By default the header IdcsMtRoleMapperProvider.IDCS_APP_HEADER is used. |`idcs-tenant-handler` |xref:{rootdir}/config/io_helidon_security_util_TokenHandler.adoc[TokenHandler] |{nbsp} |Configure token handler for IDCS Tenant ID. - By default the header IdcsMtRoleMapperProvider.IDCS_TENANT_HEADER is used. +By default the header IdcsMtRoleMapperProvider.IDCS_TENANT_HEADER is used. |`oidc-config` |xref:{rootdir}/config/io_helidon_security_providers_oidc_common_OidcConfig.adoc[OidcConfig] |{nbsp} |Use explicit io.helidon.security.providers.oidc.common.OidcConfig instance, e.g. when using it also for OIDC - provider. +provider. |`subject-types` |SubjectType[] (USER, SERVICE) |`USER` |Add a supported subject type. - If none added, io.helidon.security.SubjectType.USER is used. - If any added, only the ones added will be used (e.g. if you want to use - both io.helidon.security.SubjectType.USER and io.helidon.security.SubjectType.SERVICE, - both need to be added. +If none added, io.helidon.security.SubjectType.USER is used. +If any added, only the ones added will be used (e.g. if you want to use +both io.helidon.security.SubjectType.USER and io.helidon.security.SubjectType.SERVICE, +both need to be added. |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_idcs_mapper_IdcsRoleMapperProvider.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_idcs_mapper_IdcsRoleMapperProvider.adoc index 67b7f64bbc3..528642bc210 100644 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_idcs_mapper_IdcsRoleMapperProvider.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_security_providers_idcs_mapper_IdcsRoleMapperProvider.adoc @@ -57,15 +57,15 @@ This type provides the following service implementations: |`cache-config` |xref:{rootdir}/config/io_helidon_security_providers_common_EvictableCache.adoc[EvictableCache] |{nbsp} |Use explicit io.helidon.security.providers.common.EvictableCache for role caching. |`default-idcs-subject-type` |string |`user` |Configure subject type to use when requesting roles from IDCS. - Can be either IDCS_SUBJECT_TYPE_USER or IDCS_SUBJECT_TYPE_CLIENT. - Defaults to IDCS_SUBJECT_TYPE_USER. +Can be either IDCS_SUBJECT_TYPE_USER or IDCS_SUBJECT_TYPE_CLIENT. +Defaults to IDCS_SUBJECT_TYPE_USER. |`oidc-config` |xref:{rootdir}/config/io_helidon_security_providers_oidc_common_OidcConfig.adoc[OidcConfig] |{nbsp} |Use explicit io.helidon.security.providers.oidc.common.OidcConfig instance, e.g. when using it also for OIDC - provider. +provider. |`subject-types` |SubjectType[] (USER, SERVICE) |`USER` |Add a supported subject type. - If none added, io.helidon.security.SubjectType.USER is used. - If any added, only the ones added will be used (e.g. if you want to use - both io.helidon.security.SubjectType.USER and io.helidon.security.SubjectType.SERVICE, - both need to be added. +If none added, io.helidon.security.SubjectType.USER is used. +If any added, only the ones added will be used (e.g. if you want to use +both io.helidon.security.SubjectType.USER and io.helidon.security.SubjectType.SERVICE, +both need to be added. |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_idcs_mapper_IdcsRoleMapperProviderBase_Builder.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_idcs_mapper_IdcsRoleMapperProviderBase_Builder.adoc index 18f2c61476e..546e355da16 100644 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_idcs_mapper_IdcsRoleMapperProviderBase_Builder.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_security_providers_idcs_mapper_IdcsRoleMapperProviderBase_Builder.adoc @@ -43,15 +43,15 @@ Type: link:{javadoc-base-url}/io.helidon.security.providers.idcs.mapper.IdcsRole |key |type |default value |description |`default-idcs-subject-type` |string |`user` |Configure subject type to use when requesting roles from IDCS. - Can be either IDCS_SUBJECT_TYPE_USER or IDCS_SUBJECT_TYPE_CLIENT. - Defaults to IDCS_SUBJECT_TYPE_USER. +Can be either IDCS_SUBJECT_TYPE_USER or IDCS_SUBJECT_TYPE_CLIENT. +Defaults to IDCS_SUBJECT_TYPE_USER. |`oidc-config` |xref:{rootdir}/config/io_helidon_security_providers_oidc_common_OidcConfig.adoc[OidcConfig] |{nbsp} |Use explicit io.helidon.security.providers.oidc.common.OidcConfig instance, e.g. when using it also for OIDC - provider. +provider. |`subject-types` |SubjectType[] (USER, SERVICE) |`USER` |Add a supported subject type. - If none added, io.helidon.security.SubjectType.USER is used. - If any added, only the ones added will be used (e.g. if you want to use - both io.helidon.security.SubjectType.USER and io.helidon.security.SubjectType.SERVICE, - both need to be added. +If none added, io.helidon.security.SubjectType.USER is used. +If any added, only the ones added will be used (e.g. if you want to use +both io.helidon.security.SubjectType.USER and io.helidon.security.SubjectType.SERVICE, +both need to be added. |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_jwt_JwtProvider.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_jwt_JwtProvider.adoc index 0a69c95ecdc..92528b33934 100644 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_jwt_JwtProvider.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_security_providers_jwt_JwtProvider.adoc @@ -56,36 +56,34 @@ This type provides the following service implementations: |key |type |default value |description |`allow-impersonation` |boolean |`false` |Whether to allow impersonation by explicitly overriding - username from outbound requests using io.helidon.security.EndpointConfig.PROPERTY_OUTBOUND_ID - property. - By default this is not allowed and identity can only be propagated. +username from outbound requests using io.helidon.security.EndpointConfig.PROPERTY_OUTBOUND_ID +property. +By default this is not allowed and identity can only be propagated. |`allow-unsigned` |boolean |`false` |Configure support for unsigned JWT. - If this is set to `true` any JWT that has algorithm - set to `none` and no `kid` defined will be accepted. - Note that this has serious security impact - if JWT can be sent - from a third party, this allows the third party to send ANY JWT - and it would be accpted as valid. +If this is set to `true` any JWT that has algorithm +set to `none` and no `kid` defined will be accepted. +Note that this has serious security impact - if JWT can be sent + from a third party, this allows the third party to send ANY JWT + and it would be accpted as valid. |`atn-token.handler` |xref:{rootdir}/config/io_helidon_security_util_TokenHandler.adoc[TokenHandler] |{nbsp} |Token handler to extract username from request. |`atn-token.jwk.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |JWK resource used to verify JWTs created by other parties. |`atn-token.jwt-audience` |string |{nbsp} |Audience expected in inbound JWTs. |`atn-token.verify-signature` |boolean |`true` |Configure whether to verify signatures. - Signatures verification is enabled by default. You can configure the provider - not to verify signatures. +Signatures verification is enabled by default. You can configure the provider +not to verify signatures. - Make sure your service is properly secured on network level and only - accessible from a secure endpoint that provides the JWTs when signature verification - is disabled. If signature verification is disabled, this service will accept ANY JWT +*Make sure your service is properly secured on network level and only accessible from a secure endpoint that provides the JWTs when signature verification is disabled. If signature verification is disabled, this service will accept _ANY_ JWT* |`authenticate` |boolean |`true` |Whether to authenticate requests. |`optional` |boolean |`false` |Whether authentication is required. - By default, request will fail if the username cannot be extracted. - If set to false, request will process and this provider will abstain. +By default, request will fail if the username cannot be extracted. +If set to false, request will process and this provider will abstain. |`principal-type` |SubjectType (USER, SERVICE) |`USER` |Principal type this provider extracts (and also propagates). |`propagate` |boolean |`true` |Whether to propagate identity. |`sign-token` |xref:{rootdir}/config/io_helidon_security_providers_common_OutboundConfig.adoc[OutboundConfig] |{nbsp} |Configuration of outbound rules. |`sign-token.jwk.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |JWK resource used to sign JWTs created by us. |`sign-token.jwt-issuer` |string |{nbsp} |Issuer used to create new JWTs. |`use-jwt-groups` |boolean |`true` |Claim `groups` from JWT will be used to automatically add - groups to current subject (may be used with jakarta.annotation.security.RolesAllowed annotation). + groups to current subject (may be used with jakarta.annotation.security.RolesAllowed annotation). |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_OidcProvider.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_OidcProvider.adoc index bdf45263c19..5316da19bab 100644 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_OidcProvider.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_OidcProvider.adoc @@ -56,156 +56,193 @@ This type provides the following service implementations: |key |type |default value |description |`access-token-ip-check` |boolean |`true` |Whether to check if current IP address matches the one access token was issued for. - This check helps with cookie replay attack prevention. +This check helps with cookie replay attack prevention. |`audience` |string |{nbsp} |Audience of issued tokens. |`authorization-endpoint-uri` |URI |{nbsp} |URI of an authorization endpoint used to redirect users to for logging-in. - If not defined, it is obtained from oidcMetadata(Resource), if that is not defined - an attempt is made to use identityUri(URI)/oauth2/v1/authorize. +If not defined, it is obtained from oidcMetadata(Resource), if that is not defined +an attempt is made to use identityUri(URI)/oauth2/v1/authorize. |`base-scopes` |string |`openid` |Configure base scopes. - By default, this is DEFAULT_BASE_SCOPES. - If scope has a qualifier, it must be used here. +By default, this is DEFAULT_BASE_SCOPES. +If scope has a qualifier, it must be used here. |`check-audience` |boolean |`false` |Configure audience claim check. |`client-id` |string |{nbsp} |Client ID as generated by OIDC server. |`client-secret` |string |{nbsp} |Client secret as generated by OIDC server. - Used to authenticate this application with the server when requesting - JWT based on a code. +Used to authenticate this application with the server when requesting +JWT based on a code. |`client-timeout-millis` |Duration |`30000` |Timeout of calls using web client. |`cookie-domain` |string |{nbsp} |Domain the cookie is valid for. - Not used by default. +Not used by default. |`cookie-encryption-enabled` |boolean |`false` |Whether to encrypt token cookie created by this microservice. - Defaults to `false`. +Defaults to `false`. |`cookie-encryption-id-enabled` |boolean |`true` |Whether to encrypt id token cookie created by this microservice. - Defaults to `true`. +Defaults to `true`. |`cookie-encryption-name` |string |{nbsp} |Name of the encryption configuration available through Security.encrypt(String, byte[]) and - Security.decrypt(String, String). - If configured and encryption is enabled for any cookie, - Security MUST be configured in global or current `io.helidon.common.context.Context` (this - is done automatically in Helidon MP). +Security.decrypt(String, String). +If configured and encryption is enabled for any cookie, +Security MUST be configured in global or current `io.helidon.common.context.Context` (this +is done automatically in Helidon MP). |`cookie-encryption-password` |char[] |{nbsp} |Master password for encryption/decryption of cookies. This must be configured to the same value on each microservice - using the cookie. +using the cookie. |`cookie-encryption-refresh-enabled` |boolean |`true` |Whether to encrypt refresh token cookie created by this microservice. - Defaults to `true`. +Defaults to `true`. |`cookie-encryption-state-enabled` |boolean |`true` |Whether to encrypt state cookie created by this microservice. - Defaults to `true`. +Defaults to `true`. |`cookie-encryption-tenant-enabled` |boolean |`true` |Whether to encrypt tenant name cookie created by this microservice. - Defaults to `true`. +Defaults to `true`. |`cookie-http-only` |boolean |`true` |When using cookie, if set to true, the HttpOnly attribute will be configured. - Defaults to OidcCookieHandler.Builder.DEFAULT_HTTP_ONLY. +Defaults to OidcCookieHandler.Builder.DEFAULT_HTTP_ONLY. |`cookie-max-age-seconds` |long |{nbsp} |When using cookie, used to set MaxAge attribute of the cookie, defining how long - the cookie is valid. - Not used by default. +the cookie is valid. +Not used by default. |`cookie-name` |string |`JSESSIONID` |Name of the cookie to use. - Defaults to DEFAULT_COOKIE_NAME. +Defaults to DEFAULT_COOKIE_NAME. |`cookie-name-id-token` |string |`JSESSIONID_2` |Name of the cookie to use for id token. - Defaults to DEFAULT_COOKIE_NAME_2. +Defaults to DEFAULT_COOKIE_NAME_2. - This cookie is only used when logout is enabled, as otherwise it is not needed. - Content of this cookie is encrypted. +This cookie is only used when logout is enabled, as otherwise it is not needed. +Content of this cookie is encrypted. |`cookie-name-refresh-token` |string |`JSESSIONID_3` |The name of the cookie to use for the refresh token. - Defaults to DEFAULT_REFRESH_COOKIE_NAME. +Defaults to DEFAULT_REFRESH_COOKIE_NAME. |`cookie-name-state` |string |`JSESSIONID_3` |The name of the cookie to use for the state storage. - Defaults to DEFAULT_STATE_COOKIE_NAME. +Defaults to DEFAULT_STATE_COOKIE_NAME. |`cookie-name-tenant` |string |`HELIDON_TENANT` |The name of the cookie to use for the tenant name. - Defaults to DEFAULT_TENANT_COOKIE_NAME. +Defaults to DEFAULT_TENANT_COOKIE_NAME. |`cookie-path` |string |`/` |Path the cookie is valid for. - Defaults to "/". +Defaults to "/". |`cookie-same-site` |SameSite (LAX, STRICT, NONE) |`LAX` |When using cookie, used to set the SameSite cookie value. Can be - "Strict" or "Lax". +"Strict" or "Lax". |`cookie-secure` |boolean |`false` |When using cookie, if set to true, the Secure attribute will be configured. - Defaults to false. +Defaults to false. |`cookie-use` |boolean |`true` |Whether to use cookie to store JWT between requests. - Defaults to DEFAULT_COOKIE_USE. +Defaults to DEFAULT_COOKIE_USE. |`cors` |xref:{rootdir}/config/io_helidon_cors_CrossOriginConfig.adoc[CrossOriginConfig] |{nbsp} |Assign cross-origin resource sharing settings. |`force-https-redirects` |boolean |`false` |Force HTTPS for redirects to identity provider. - Defaults to `false`. +Defaults to `false`. |`frontend-uri` |string |{nbsp} |Full URI of this application that is visible from user browser. - Used to redirect request back from identity server after successful login. +Used to redirect request back from identity server after successful login. |`header-token` |xref:{rootdir}/config/io_helidon_security_util_TokenHandler.adoc[TokenHandler] |{nbsp} |A TokenHandler to - process header containing a JWT. - Default is "Authorization" header with a prefix "bearer ". +process header containing a JWT. +Default is "Authorization" header with a prefix "bearer ". |`header-use` |boolean |`true` |Whether to expect JWT in a header field. |`id-token-signature-validation` |boolean |`true` |Whether id token signature check should be enabled. - Signature check is enabled by default, and it is highly recommended to not change that. - Change this setting only when you really know what you are doing, otherwise it could case security issues. +Signature check is enabled by default, and it is highly recommended to not change that. +Change this setting only when you really know what you are doing, otherwise it could case security issues. |`identity-uri` |URI |{nbsp} |URI of the identity server, base used to retrieve OIDC metadata. |`introspect-endpoint-uri` |URI |{nbsp} |Endpoint to use to validate JWT. - Either use this or set signJwk(JwkKeys) or signJwk(Resource). +Either use this or set signJwk(JwkKeys) or signJwk(Resource). |`issuer` |string |{nbsp} |Issuer of issued tokens. |`max-redirects` |int |`5` |Configure maximal number of redirects when redirecting to an OIDC provider within a single authentication - attempt. +attempt. - Defaults to DEFAULT_MAX_REDIRECTS +Defaults to DEFAULT_MAX_REDIRECTS |`oidc-metadata-well-known` |boolean |`true` |If set to true, metadata will be loaded from default (well known) - location, unless it is explicitly defined using oidc-metadata-resource. If set to false, it would not be loaded - even if oidc-metadata-resource is not defined. In such a case all URIs must be explicitly defined (e.g. - token-endpoint-uri). +location, unless it is explicitly defined using oidc-metadata-resource. If set to false, it would not be loaded +even if oidc-metadata-resource is not defined. In such a case all URIs must be explicitly defined (e.g. +token-endpoint-uri). |`oidc-metadata.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Resource configuration for OIDC Metadata - containing endpoints to various identity services, as well as information about the identity server. +containing endpoints to various identity services, as well as information about the identity server. |`optional` |boolean |`false` |Whether authentication is required. - By default, request will fail if the authentication cannot be verified. - If set to true, request will process and this provider will abstain. +By default, request will fail if the authentication cannot be verified. +If set to true, request will process and this provider will abstain. |`optional-audience` |boolean |`false` |Allow audience claim to be optional. |`outbound` |xref:{rootdir}/config/io_helidon_security_providers_common_OutboundTarget.adoc[OutboundTarget[]] |{nbsp} |Add a new target configuration. |`propagate` |boolean |`false` |Whether to propagate identity. |`proxy-host` |string |{nbsp} |Proxy host to use. When defined, triggers usage of proxy for HTTP requests. - Setting to empty String has the same meaning as setting to null - disables proxy. +Setting to empty String has the same meaning as setting to null - disables proxy. |`proxy-port` |int |`80` |Proxy port. - Defaults to DEFAULT_PROXY_PORT +Defaults to DEFAULT_PROXY_PORT |`proxy-protocol` |string |`http` |Proxy protocol to use when proxy is used. - Defaults to DEFAULT_PROXY_PROTOCOL. +Defaults to DEFAULT_PROXY_PROTOCOL. |`query-id-token-param-name` |string |`id_token` |Name of a query parameter that contains the JWT id token when parameter is used. |`query-param-name` |string |`accessToken` |Name of a query parameter that contains the JWT access token when parameter is used. |`query-param-tenant-name` |string |`h_tenant` |Name of a query parameter that contains the tenant name when the parameter is used. - Defaults to DEFAULT_TENANT_PARAM_NAME. +Defaults to DEFAULT_TENANT_PARAM_NAME. |`query-param-use` |boolean |`false` |Whether to use a query parameter to send JWT token from application to this - server. +server. |`redirect` |boolean |`false` |By default, the client should redirect to the identity server for the user to log in. - This behavior can be overridden by setting redirect to false. When token is not present in the request, the client - will not redirect and just return appropriate error response code. +This behavior can be overridden by setting redirect to false. When token is not present in the request, the client +will not redirect and just return appropriate error response code. |`redirect-attempt-param` |string |`h_ra` |Configure the parameter used to store the number of attempts in redirect. - Defaults to DEFAULT_ATTEMPT_PARAM +Defaults to DEFAULT_ATTEMPT_PARAM |`redirect-uri` |string |`/oidc/redirect` |URI to register web server component on, used by the OIDC server to - redirect authorization requests to after a user logs in or approves - scopes. - Note that usually the redirect URI configured here must be the - same one as configured on OIDC server. +redirect authorization requests to after a user logs in or approves +scopes. +Note that usually the redirect URI configured here must be the +same one as configured on OIDC server. - Defaults to DEFAULT_REDIRECT_URI +Defaults to DEFAULT_REDIRECT_URI |`relative-uris` |boolean |`false` |Can be set to `true` to force the use of relative URIs in all requests, - regardless of the presence or absence of proxies or no-proxy lists. By default, - requests that use the Proxy will have absolute URIs. Set this flag to `true` - if the host is unable to accept absolute URIs. - Defaults to DEFAULT_RELATIVE_URIS. +regardless of the presence or absence of proxies or no-proxy lists. By default, +requests that use the Proxy will have absolute URIs. Set this flag to `true` +if the host is unable to accept absolute URIs. +Defaults to DEFAULT_RELATIVE_URIS. |`scope-audience` |string |{nbsp} |Audience of the scope required by this application. This is prefixed to - the scope name when requesting scopes from the identity server. - Defaults to empty string. +the scope name when requesting scopes from the identity server. +Defaults to empty string. |`server-type` |string |`@default` |Configure one of the supported types of identity servers. - If the type does not have an explicit mapping, a warning is logged and the default implementation is used. +If the type does not have an explicit mapping, a warning is logged and the default implementation is used. |`sign-jwk.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |A resource pointing to JWK with public keys of signing certificates used - to validate JWT. +to validate JWT. |`tenants` |xref:{rootdir}/config/io_helidon_security_providers_oidc_common_TenantConfig.adoc[TenantConfig] |{nbsp} |Configurations of the tenants |`token-endpoint-auth` |ClientAuthentication (CLIENT_SECRET_BASIC, CLIENT_SECRET_POST, CLIENT_SECRET_JWT, PRIVATE_KEY_JWT, NONE) |`CLIENT_SECRET_BASIC` |Type of authentication to use when invoking the token endpoint. - Current supported options: +Current supported options: - io.helidon.security.providers.oidc.common.OidcConfig.ClientAuthentication.CLIENT_SECRET_BASIC - io.helidon.security.providers.oidc.common.OidcConfig.ClientAuthentication.CLIENT_SECRET_POST - io.helidon.security.providers.oidc.common.OidcConfig.ClientAuthentication.NONE +Allowed values: + +- `CLIENT_SECRET_BASIC`: Clients that have received a client_secret value from the Authorization Server authenticate with the Authorization +Server in accordance with Section 2.3.1 of OAuth 2.0 [RFC6749] using the HTTP Basic authentication scheme. +This is the default client authentication. +- `CLIENT_SECRET_POST`: Clients that have received a client_secret value from the Authorization Server, authenticate with the Authorization +Server in accordance with Section 2.3.1 of OAuth 2.0 [RFC6749] by including the Client Credentials in the request body. +- `CLIENT_SECRET_JWT`: Clients that have received a client_secret value from the Authorization Server create a JWT using an HMAC SHA +algorithm, such as HMAC SHA-256. The HMAC (Hash-based Message Authentication Code) is calculated using the octets of +the UTF-8 representation of the client_secret as the shared key. +The Client authenticates in accordance with JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and +Authorization Grants [OAuth.JWT] and Assertion Framework for OAuth 2.0 Client Authentication and Authorization +Grants [OAuth.Assertions]. + +The JWT MUST contain the following REQUIRED Claim Values and MAY contain the following +OPTIONAL Claim Values. + +Required: +`iss, sub, aud, jti, exp` + +Optional: +`iat` +- `PRIVATE_KEY_JWT`: Clients that have registered a public key sign a JWT using that key. The Client authenticates in accordance with +JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants [OAuth.JWT] and Assertion +Framework for OAuth 2.0 Client Authentication and Authorization Grants [OAuth.Assertions]. + +The JWT MUST contain the following REQUIRED Claim Values and MAY contain the following +OPTIONAL Claim Values. + +Required: +`iss, sub, aud, jti, exp` + +Optional: +`iat` +- `NONE`: The Client does not authenticate itself at the Token Endpoint, either because it uses only the Implicit Flow (and so +does not use the Token Endpoint) or because it is a Public Client with no Client Secret or other authentication +mechanism. |`token-endpoint-uri` |URI |{nbsp} |URI of a token endpoint used to obtain a JWT based on the authentication - code. - If not defined, it is obtained from oidcMetadata(Resource), if that is not defined - an attempt is made to use identityUri(URI)/oauth2/v1/token. +code. +If not defined, it is obtained from oidcMetadata(Resource), if that is not defined +an attempt is made to use identityUri(URI)/oauth2/v1/token. |`token-signature-validation` |boolean |`true` |Whether access token signature check should be enabled. - Signature check is enabled by default, and it is highly recommended to not change that. - Change this setting only when you really know what you are doing, otherwise it could case security issues. +Signature check is enabled by default, and it is highly recommended to not change that. +Change this setting only when you really know what you are doing, otherwise it could case security issues. |`use-jwt-groups` |boolean |`true` |Claim `groups` from JWT will be used to automatically add - groups to current subject (may be used with jakarta.annotation.security.RolesAllowed annotation). + groups to current subject (may be used with jakarta.annotation.security.RolesAllowed annotation). |`validate-jwt-with-jwk` |boolean |`true` |Use JWK (a set of keys to validate signatures of JWT) to validate tokens. - Use this method when you want to use default values for JWK or introspection endpoint URI. +Use this method when you want to use default values for JWK or introspection endpoint URI. |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_common_BaseBuilder.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_common_BaseBuilder.adoc index 0d030dac053..becac070edd 100644 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_common_BaseBuilder.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_common_BaseBuilder.adoc @@ -45,50 +45,87 @@ Type: link:{javadoc-base-url}/io.helidon.security.providers.oidc.common/io/helid |`audience` |string |{nbsp} |Audience of issued tokens. |`authorization-endpoint-uri` |URI |{nbsp} |URI of an authorization endpoint used to redirect users to for logging-in. - If not defined, it is obtained from oidcMetadata(Resource), if that is not defined - an attempt is made to use identityUri(URI)/oauth2/v1/authorize. +If not defined, it is obtained from oidcMetadata(Resource), if that is not defined +an attempt is made to use identityUri(URI)/oauth2/v1/authorize. |`base-scopes` |string |`openid` |Configure base scopes. - By default, this is DEFAULT_BASE_SCOPES. - If scope has a qualifier, it must be used here. +By default, this is DEFAULT_BASE_SCOPES. +If scope has a qualifier, it must be used here. |`check-audience` |boolean |`false` |Configure audience claim check. |`client-id` |string |{nbsp} |Client ID as generated by OIDC server. |`client-secret` |string |{nbsp} |Client secret as generated by OIDC server. - Used to authenticate this application with the server when requesting - JWT based on a code. +Used to authenticate this application with the server when requesting +JWT based on a code. |`client-timeout-millis` |Duration |`30000` |Timeout of calls using web client. |`identity-uri` |URI |{nbsp} |URI of the identity server, base used to retrieve OIDC metadata. |`introspect-endpoint-uri` |URI |{nbsp} |Endpoint to use to validate JWT. - Either use this or set signJwk(JwkKeys) or signJwk(Resource). +Either use this or set signJwk(JwkKeys) or signJwk(Resource). |`issuer` |string |{nbsp} |Issuer of issued tokens. |`oidc-metadata-well-known` |boolean |`true` |If set to true, metadata will be loaded from default (well known) - location, unless it is explicitly defined using oidc-metadata-resource. If set to false, it would not be loaded - even if oidc-metadata-resource is not defined. In such a case all URIs must be explicitly defined (e.g. - token-endpoint-uri). +location, unless it is explicitly defined using oidc-metadata-resource. If set to false, it would not be loaded +even if oidc-metadata-resource is not defined. In such a case all URIs must be explicitly defined (e.g. +token-endpoint-uri). |`oidc-metadata.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Resource configuration for OIDC Metadata - containing endpoints to various identity services, as well as information about the identity server. +containing endpoints to various identity services, as well as information about the identity server. |`optional-audience` |boolean |`false` |Allow audience claim to be optional. |`scope-audience` |string |{nbsp} |Audience of the scope required by this application. This is prefixed to - the scope name when requesting scopes from the identity server. - Defaults to empty string. +the scope name when requesting scopes from the identity server. +Defaults to empty string. |`server-type` |string |`@default` |Configure one of the supported types of identity servers. - If the type does not have an explicit mapping, a warning is logged and the default implementation is used. +If the type does not have an explicit mapping, a warning is logged and the default implementation is used. |`sign-jwk.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |A resource pointing to JWK with public keys of signing certificates used - to validate JWT. +to validate JWT. |`token-endpoint-auth` |ClientAuthentication (CLIENT_SECRET_BASIC, CLIENT_SECRET_POST, CLIENT_SECRET_JWT, PRIVATE_KEY_JWT, NONE) |`CLIENT_SECRET_BASIC` |Type of authentication to use when invoking the token endpoint. - Current supported options: +Current supported options: - io.helidon.security.providers.oidc.common.OidcConfig.ClientAuthentication.CLIENT_SECRET_BASIC - io.helidon.security.providers.oidc.common.OidcConfig.ClientAuthentication.CLIENT_SECRET_POST - io.helidon.security.providers.oidc.common.OidcConfig.ClientAuthentication.NONE +Allowed values: + +- `CLIENT_SECRET_BASIC`: Clients that have received a client_secret value from the Authorization Server authenticate with the Authorization +Server in accordance with Section 2.3.1 of OAuth 2.0 [RFC6749] using the HTTP Basic authentication scheme. +This is the default client authentication. +- `CLIENT_SECRET_POST`: Clients that have received a client_secret value from the Authorization Server, authenticate with the Authorization +Server in accordance with Section 2.3.1 of OAuth 2.0 [RFC6749] by including the Client Credentials in the request body. +- `CLIENT_SECRET_JWT`: Clients that have received a client_secret value from the Authorization Server create a JWT using an HMAC SHA +algorithm, such as HMAC SHA-256. The HMAC (Hash-based Message Authentication Code) is calculated using the octets of +the UTF-8 representation of the client_secret as the shared key. +The Client authenticates in accordance with JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and +Authorization Grants [OAuth.JWT] and Assertion Framework for OAuth 2.0 Client Authentication and Authorization +Grants [OAuth.Assertions]. + +The JWT MUST contain the following REQUIRED Claim Values and MAY contain the following +OPTIONAL Claim Values. + +Required: +`iss, sub, aud, jti, exp` + +Optional: +`iat` +- `PRIVATE_KEY_JWT`: Clients that have registered a public key sign a JWT using that key. The Client authenticates in accordance with +JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants [OAuth.JWT] and Assertion +Framework for OAuth 2.0 Client Authentication and Authorization Grants [OAuth.Assertions]. + +The JWT MUST contain the following REQUIRED Claim Values and MAY contain the following +OPTIONAL Claim Values. + +Required: +`iss, sub, aud, jti, exp` + +Optional: +`iat` +- `NONE`: The Client does not authenticate itself at the Token Endpoint, either because it uses only the Implicit Flow (and so +does not use the Token Endpoint) or because it is a Public Client with no Client Secret or other authentication +mechanism. |`token-endpoint-uri` |URI |{nbsp} |URI of a token endpoint used to obtain a JWT based on the authentication - code. - If not defined, it is obtained from oidcMetadata(Resource), if that is not defined - an attempt is made to use identityUri(URI)/oauth2/v1/token. +code. +If not defined, it is obtained from oidcMetadata(Resource), if that is not defined +an attempt is made to use identityUri(URI)/oauth2/v1/token. |`validate-jwt-with-jwk` |boolean |`true` |Use JWK (a set of keys to validate signatures of JWT) to validate tokens. - Use this method when you want to use default values for JWK or introspection endpoint URI. +Use this method when you want to use default values for JWK or introspection endpoint URI. |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_common_OidcConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_common_OidcConfig.adoc index 2b2f8552905..17742c33dfa 100644 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_common_OidcConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_common_OidcConfig.adoc @@ -45,149 +45,186 @@ Type: link:{javadoc-base-url}/io.helidon.security.providers.oidc.common/io/helid |key |type |default value |description |`access-token-ip-check` |boolean |`true` |Whether to check if current IP address matches the one access token was issued for. - This check helps with cookie replay attack prevention. +This check helps with cookie replay attack prevention. |`audience` |string |{nbsp} |Audience of issued tokens. |`authorization-endpoint-uri` |URI |{nbsp} |URI of an authorization endpoint used to redirect users to for logging-in. - If not defined, it is obtained from oidcMetadata(Resource), if that is not defined - an attempt is made to use identityUri(URI)/oauth2/v1/authorize. +If not defined, it is obtained from oidcMetadata(Resource), if that is not defined +an attempt is made to use identityUri(URI)/oauth2/v1/authorize. |`base-scopes` |string |`openid` |Configure base scopes. - By default, this is DEFAULT_BASE_SCOPES. - If scope has a qualifier, it must be used here. +By default, this is DEFAULT_BASE_SCOPES. +If scope has a qualifier, it must be used here. |`check-audience` |boolean |`false` |Configure audience claim check. |`client-id` |string |{nbsp} |Client ID as generated by OIDC server. |`client-secret` |string |{nbsp} |Client secret as generated by OIDC server. - Used to authenticate this application with the server when requesting - JWT based on a code. +Used to authenticate this application with the server when requesting +JWT based on a code. |`client-timeout-millis` |Duration |`30000` |Timeout of calls using web client. |`cookie-domain` |string |{nbsp} |Domain the cookie is valid for. - Not used by default. +Not used by default. |`cookie-encryption-enabled` |boolean |`false` |Whether to encrypt token cookie created by this microservice. - Defaults to `false`. +Defaults to `false`. |`cookie-encryption-id-enabled` |boolean |`true` |Whether to encrypt id token cookie created by this microservice. - Defaults to `true`. +Defaults to `true`. |`cookie-encryption-name` |string |{nbsp} |Name of the encryption configuration available through Security.encrypt(String, byte[]) and - Security.decrypt(String, String). - If configured and encryption is enabled for any cookie, - Security MUST be configured in global or current `io.helidon.common.context.Context` (this - is done automatically in Helidon MP). +Security.decrypt(String, String). +If configured and encryption is enabled for any cookie, +Security MUST be configured in global or current `io.helidon.common.context.Context` (this +is done automatically in Helidon MP). |`cookie-encryption-password` |char[] |{nbsp} |Master password for encryption/decryption of cookies. This must be configured to the same value on each microservice - using the cookie. +using the cookie. |`cookie-encryption-refresh-enabled` |boolean |`true` |Whether to encrypt refresh token cookie created by this microservice. - Defaults to `true`. +Defaults to `true`. |`cookie-encryption-state-enabled` |boolean |`true` |Whether to encrypt state cookie created by this microservice. - Defaults to `true`. +Defaults to `true`. |`cookie-encryption-tenant-enabled` |boolean |`true` |Whether to encrypt tenant name cookie created by this microservice. - Defaults to `true`. +Defaults to `true`. |`cookie-http-only` |boolean |`true` |When using cookie, if set to true, the HttpOnly attribute will be configured. - Defaults to OidcCookieHandler.Builder.DEFAULT_HTTP_ONLY. +Defaults to OidcCookieHandler.Builder.DEFAULT_HTTP_ONLY. |`cookie-max-age-seconds` |long |{nbsp} |When using cookie, used to set MaxAge attribute of the cookie, defining how long - the cookie is valid. - Not used by default. +the cookie is valid. +Not used by default. |`cookie-name` |string |`JSESSIONID` |Name of the cookie to use. - Defaults to DEFAULT_COOKIE_NAME. +Defaults to DEFAULT_COOKIE_NAME. |`cookie-name-id-token` |string |`JSESSIONID_2` |Name of the cookie to use for id token. - Defaults to DEFAULT_COOKIE_NAME_2. +Defaults to DEFAULT_COOKIE_NAME_2. - This cookie is only used when logout is enabled, as otherwise it is not needed. - Content of this cookie is encrypted. +This cookie is only used when logout is enabled, as otherwise it is not needed. +Content of this cookie is encrypted. |`cookie-name-refresh-token` |string |`JSESSIONID_3` |The name of the cookie to use for the refresh token. - Defaults to DEFAULT_REFRESH_COOKIE_NAME. +Defaults to DEFAULT_REFRESH_COOKIE_NAME. |`cookie-name-state` |string |`JSESSIONID_3` |The name of the cookie to use for the state storage. - Defaults to DEFAULT_STATE_COOKIE_NAME. +Defaults to DEFAULT_STATE_COOKIE_NAME. |`cookie-name-tenant` |string |`HELIDON_TENANT` |The name of the cookie to use for the tenant name. - Defaults to DEFAULT_TENANT_COOKIE_NAME. +Defaults to DEFAULT_TENANT_COOKIE_NAME. |`cookie-path` |string |`/` |Path the cookie is valid for. - Defaults to "/". +Defaults to "/". |`cookie-same-site` |SameSite (LAX, STRICT, NONE) |`LAX` |When using cookie, used to set the SameSite cookie value. Can be - "Strict" or "Lax". +"Strict" or "Lax". |`cookie-secure` |boolean |`false` |When using cookie, if set to true, the Secure attribute will be configured. - Defaults to false. +Defaults to false. |`cookie-use` |boolean |`true` |Whether to use cookie to store JWT between requests. - Defaults to DEFAULT_COOKIE_USE. +Defaults to DEFAULT_COOKIE_USE. |`cors` |xref:{rootdir}/config/io_helidon_cors_CrossOriginConfig.adoc[CrossOriginConfig] |{nbsp} |Assign cross-origin resource sharing settings. |`force-https-redirects` |boolean |`false` |Force HTTPS for redirects to identity provider. - Defaults to `false`. +Defaults to `false`. |`frontend-uri` |string |{nbsp} |Full URI of this application that is visible from user browser. - Used to redirect request back from identity server after successful login. +Used to redirect request back from identity server after successful login. |`header-token` |xref:{rootdir}/config/io_helidon_security_util_TokenHandler.adoc[TokenHandler] |{nbsp} |A TokenHandler to - process header containing a JWT. - Default is "Authorization" header with a prefix "bearer ". +process header containing a JWT. +Default is "Authorization" header with a prefix "bearer ". |`header-use` |boolean |`true` |Whether to expect JWT in a header field. |`id-token-signature-validation` |boolean |`true` |Whether id token signature check should be enabled. - Signature check is enabled by default, and it is highly recommended to not change that. - Change this setting only when you really know what you are doing, otherwise it could case security issues. +Signature check is enabled by default, and it is highly recommended to not change that. +Change this setting only when you really know what you are doing, otherwise it could case security issues. |`identity-uri` |URI |{nbsp} |URI of the identity server, base used to retrieve OIDC metadata. |`introspect-endpoint-uri` |URI |{nbsp} |Endpoint to use to validate JWT. - Either use this or set signJwk(JwkKeys) or signJwk(Resource). +Either use this or set signJwk(JwkKeys) or signJwk(Resource). |`issuer` |string |{nbsp} |Issuer of issued tokens. |`max-redirects` |int |`5` |Configure maximal number of redirects when redirecting to an OIDC provider within a single authentication - attempt. +attempt. - Defaults to DEFAULT_MAX_REDIRECTS +Defaults to DEFAULT_MAX_REDIRECTS |`oidc-metadata-well-known` |boolean |`true` |If set to true, metadata will be loaded from default (well known) - location, unless it is explicitly defined using oidc-metadata-resource. If set to false, it would not be loaded - even if oidc-metadata-resource is not defined. In such a case all URIs must be explicitly defined (e.g. - token-endpoint-uri). +location, unless it is explicitly defined using oidc-metadata-resource. If set to false, it would not be loaded +even if oidc-metadata-resource is not defined. In such a case all URIs must be explicitly defined (e.g. +token-endpoint-uri). |`oidc-metadata.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Resource configuration for OIDC Metadata - containing endpoints to various identity services, as well as information about the identity server. +containing endpoints to various identity services, as well as information about the identity server. |`optional-audience` |boolean |`false` |Allow audience claim to be optional. |`proxy-host` |string |{nbsp} |Proxy host to use. When defined, triggers usage of proxy for HTTP requests. - Setting to empty String has the same meaning as setting to null - disables proxy. +Setting to empty String has the same meaning as setting to null - disables proxy. |`proxy-port` |int |`80` |Proxy port. - Defaults to DEFAULT_PROXY_PORT +Defaults to DEFAULT_PROXY_PORT |`proxy-protocol` |string |`http` |Proxy protocol to use when proxy is used. - Defaults to DEFAULT_PROXY_PROTOCOL. +Defaults to DEFAULT_PROXY_PROTOCOL. |`query-id-token-param-name` |string |`id_token` |Name of a query parameter that contains the JWT id token when parameter is used. |`query-param-name` |string |`accessToken` |Name of a query parameter that contains the JWT access token when parameter is used. |`query-param-tenant-name` |string |`h_tenant` |Name of a query parameter that contains the tenant name when the parameter is used. - Defaults to DEFAULT_TENANT_PARAM_NAME. +Defaults to DEFAULT_TENANT_PARAM_NAME. |`query-param-use` |boolean |`false` |Whether to use a query parameter to send JWT token from application to this - server. +server. |`redirect` |boolean |`false` |By default, the client should redirect to the identity server for the user to log in. - This behavior can be overridden by setting redirect to false. When token is not present in the request, the client - will not redirect and just return appropriate error response code. +This behavior can be overridden by setting redirect to false. When token is not present in the request, the client +will not redirect and just return appropriate error response code. |`redirect-attempt-param` |string |`h_ra` |Configure the parameter used to store the number of attempts in redirect. - Defaults to DEFAULT_ATTEMPT_PARAM +Defaults to DEFAULT_ATTEMPT_PARAM |`redirect-uri` |string |`/oidc/redirect` |URI to register web server component on, used by the OIDC server to - redirect authorization requests to after a user logs in or approves - scopes. - Note that usually the redirect URI configured here must be the - same one as configured on OIDC server. +redirect authorization requests to after a user logs in or approves +scopes. +Note that usually the redirect URI configured here must be the +same one as configured on OIDC server. - Defaults to DEFAULT_REDIRECT_URI +Defaults to DEFAULT_REDIRECT_URI |`relative-uris` |boolean |`false` |Can be set to `true` to force the use of relative URIs in all requests, - regardless of the presence or absence of proxies or no-proxy lists. By default, - requests that use the Proxy will have absolute URIs. Set this flag to `true` - if the host is unable to accept absolute URIs. - Defaults to DEFAULT_RELATIVE_URIS. +regardless of the presence or absence of proxies or no-proxy lists. By default, +requests that use the Proxy will have absolute URIs. Set this flag to `true` +if the host is unable to accept absolute URIs. +Defaults to DEFAULT_RELATIVE_URIS. |`scope-audience` |string |{nbsp} |Audience of the scope required by this application. This is prefixed to - the scope name when requesting scopes from the identity server. - Defaults to empty string. +the scope name when requesting scopes from the identity server. +Defaults to empty string. |`server-type` |string |`@default` |Configure one of the supported types of identity servers. - If the type does not have an explicit mapping, a warning is logged and the default implementation is used. +If the type does not have an explicit mapping, a warning is logged and the default implementation is used. |`sign-jwk.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |A resource pointing to JWK with public keys of signing certificates used - to validate JWT. +to validate JWT. |`tenants` |xref:{rootdir}/config/io_helidon_security_providers_oidc_common_TenantConfig.adoc[TenantConfig] |{nbsp} |Configurations of the tenants |`token-endpoint-auth` |ClientAuthentication (CLIENT_SECRET_BASIC, CLIENT_SECRET_POST, CLIENT_SECRET_JWT, PRIVATE_KEY_JWT, NONE) |`CLIENT_SECRET_BASIC` |Type of authentication to use when invoking the token endpoint. - Current supported options: +Current supported options: - io.helidon.security.providers.oidc.common.OidcConfig.ClientAuthentication.CLIENT_SECRET_BASIC - io.helidon.security.providers.oidc.common.OidcConfig.ClientAuthentication.CLIENT_SECRET_POST - io.helidon.security.providers.oidc.common.OidcConfig.ClientAuthentication.NONE +Allowed values: + +- `CLIENT_SECRET_BASIC`: Clients that have received a client_secret value from the Authorization Server authenticate with the Authorization +Server in accordance with Section 2.3.1 of OAuth 2.0 [RFC6749] using the HTTP Basic authentication scheme. +This is the default client authentication. +- `CLIENT_SECRET_POST`: Clients that have received a client_secret value from the Authorization Server, authenticate with the Authorization +Server in accordance with Section 2.3.1 of OAuth 2.0 [RFC6749] by including the Client Credentials in the request body. +- `CLIENT_SECRET_JWT`: Clients that have received a client_secret value from the Authorization Server create a JWT using an HMAC SHA +algorithm, such as HMAC SHA-256. The HMAC (Hash-based Message Authentication Code) is calculated using the octets of +the UTF-8 representation of the client_secret as the shared key. +The Client authenticates in accordance with JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and +Authorization Grants [OAuth.JWT] and Assertion Framework for OAuth 2.0 Client Authentication and Authorization +Grants [OAuth.Assertions]. + +The JWT MUST contain the following REQUIRED Claim Values and MAY contain the following +OPTIONAL Claim Values. + +Required: +`iss, sub, aud, jti, exp` + +Optional: +`iat` +- `PRIVATE_KEY_JWT`: Clients that have registered a public key sign a JWT using that key. The Client authenticates in accordance with +JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants [OAuth.JWT] and Assertion +Framework for OAuth 2.0 Client Authentication and Authorization Grants [OAuth.Assertions]. + +The JWT MUST contain the following REQUIRED Claim Values and MAY contain the following +OPTIONAL Claim Values. + +Required: +`iss, sub, aud, jti, exp` + +Optional: +`iat` +- `NONE`: The Client does not authenticate itself at the Token Endpoint, either because it uses only the Implicit Flow (and so +does not use the Token Endpoint) or because it is a Public Client with no Client Secret or other authentication +mechanism. |`token-endpoint-uri` |URI |{nbsp} |URI of a token endpoint used to obtain a JWT based on the authentication - code. - If not defined, it is obtained from oidcMetadata(Resource), if that is not defined - an attempt is made to use identityUri(URI)/oauth2/v1/token. +code. +If not defined, it is obtained from oidcMetadata(Resource), if that is not defined +an attempt is made to use identityUri(URI)/oauth2/v1/token. |`token-signature-validation` |boolean |`true` |Whether access token signature check should be enabled. - Signature check is enabled by default, and it is highly recommended to not change that. - Change this setting only when you really know what you are doing, otherwise it could case security issues. +Signature check is enabled by default, and it is highly recommended to not change that. +Change this setting only when you really know what you are doing, otherwise it could case security issues. |`validate-jwt-with-jwk` |boolean |`true` |Use JWK (a set of keys to validate signatures of JWT) to validate tokens. - Use this method when you want to use default values for JWK or introspection endpoint URI. +Use this method when you want to use default values for JWK or introspection endpoint URI. |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_common_TenantConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_common_TenantConfig.adoc index 633a3eeac59..eb160f72a0e 100644 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_common_TenantConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_common_TenantConfig.adoc @@ -56,50 +56,87 @@ Type: link:{javadoc-base-url}/io.helidon.security.providers.oidc.common/io/helid |`audience` |string |{nbsp} |Audience of issued tokens. |`authorization-endpoint-uri` |URI |{nbsp} |URI of an authorization endpoint used to redirect users to for logging-in. - If not defined, it is obtained from oidcMetadata(Resource), if that is not defined - an attempt is made to use identityUri(URI)/oauth2/v1/authorize. +If not defined, it is obtained from oidcMetadata(Resource), if that is not defined +an attempt is made to use identityUri(URI)/oauth2/v1/authorize. |`base-scopes` |string |`openid` |Configure base scopes. - By default, this is DEFAULT_BASE_SCOPES. - If scope has a qualifier, it must be used here. +By default, this is DEFAULT_BASE_SCOPES. +If scope has a qualifier, it must be used here. |`check-audience` |boolean |`false` |Configure audience claim check. |`client-id` |string |{nbsp} |Client ID as generated by OIDC server. |`client-secret` |string |{nbsp} |Client secret as generated by OIDC server. - Used to authenticate this application with the server when requesting - JWT based on a code. +Used to authenticate this application with the server when requesting +JWT based on a code. |`client-timeout-millis` |Duration |`30000` |Timeout of calls using web client. |`identity-uri` |URI |{nbsp} |URI of the identity server, base used to retrieve OIDC metadata. |`introspect-endpoint-uri` |URI |{nbsp} |Endpoint to use to validate JWT. - Either use this or set signJwk(JwkKeys) or signJwk(Resource). +Either use this or set signJwk(JwkKeys) or signJwk(Resource). |`issuer` |string |{nbsp} |Issuer of issued tokens. |`oidc-metadata-well-known` |boolean |`true` |If set to true, metadata will be loaded from default (well known) - location, unless it is explicitly defined using oidc-metadata-resource. If set to false, it would not be loaded - even if oidc-metadata-resource is not defined. In such a case all URIs must be explicitly defined (e.g. - token-endpoint-uri). +location, unless it is explicitly defined using oidc-metadata-resource. If set to false, it would not be loaded +even if oidc-metadata-resource is not defined. In such a case all URIs must be explicitly defined (e.g. +token-endpoint-uri). |`oidc-metadata.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Resource configuration for OIDC Metadata - containing endpoints to various identity services, as well as information about the identity server. +containing endpoints to various identity services, as well as information about the identity server. |`optional-audience` |boolean |`false` |Allow audience claim to be optional. |`scope-audience` |string |{nbsp} |Audience of the scope required by this application. This is prefixed to - the scope name when requesting scopes from the identity server. - Defaults to empty string. +the scope name when requesting scopes from the identity server. +Defaults to empty string. |`server-type` |string |`@default` |Configure one of the supported types of identity servers. - If the type does not have an explicit mapping, a warning is logged and the default implementation is used. +If the type does not have an explicit mapping, a warning is logged and the default implementation is used. |`sign-jwk.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |A resource pointing to JWK with public keys of signing certificates used - to validate JWT. +to validate JWT. |`token-endpoint-auth` |ClientAuthentication (CLIENT_SECRET_BASIC, CLIENT_SECRET_POST, CLIENT_SECRET_JWT, PRIVATE_KEY_JWT, NONE) |`CLIENT_SECRET_BASIC` |Type of authentication to use when invoking the token endpoint. - Current supported options: +Current supported options: - io.helidon.security.providers.oidc.common.OidcConfig.ClientAuthentication.CLIENT_SECRET_BASIC - io.helidon.security.providers.oidc.common.OidcConfig.ClientAuthentication.CLIENT_SECRET_POST - io.helidon.security.providers.oidc.common.OidcConfig.ClientAuthentication.NONE +Allowed values: + +- `CLIENT_SECRET_BASIC`: Clients that have received a client_secret value from the Authorization Server authenticate with the Authorization +Server in accordance with Section 2.3.1 of OAuth 2.0 [RFC6749] using the HTTP Basic authentication scheme. +This is the default client authentication. +- `CLIENT_SECRET_POST`: Clients that have received a client_secret value from the Authorization Server, authenticate with the Authorization +Server in accordance with Section 2.3.1 of OAuth 2.0 [RFC6749] by including the Client Credentials in the request body. +- `CLIENT_SECRET_JWT`: Clients that have received a client_secret value from the Authorization Server create a JWT using an HMAC SHA +algorithm, such as HMAC SHA-256. The HMAC (Hash-based Message Authentication Code) is calculated using the octets of +the UTF-8 representation of the client_secret as the shared key. +The Client authenticates in accordance with JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and +Authorization Grants [OAuth.JWT] and Assertion Framework for OAuth 2.0 Client Authentication and Authorization +Grants [OAuth.Assertions]. + +The JWT MUST contain the following REQUIRED Claim Values and MAY contain the following +OPTIONAL Claim Values. + +Required: +`iss, sub, aud, jti, exp` + +Optional: +`iat` +- `PRIVATE_KEY_JWT`: Clients that have registered a public key sign a JWT using that key. The Client authenticates in accordance with +JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants [OAuth.JWT] and Assertion +Framework for OAuth 2.0 Client Authentication and Authorization Grants [OAuth.Assertions]. + +The JWT MUST contain the following REQUIRED Claim Values and MAY contain the following +OPTIONAL Claim Values. + +Required: +`iss, sub, aud, jti, exp` + +Optional: +`iat` +- `NONE`: The Client does not authenticate itself at the Token Endpoint, either because it uses only the Implicit Flow (and so +does not use the Token Endpoint) or because it is a Public Client with no Client Secret or other authentication +mechanism. |`token-endpoint-uri` |URI |{nbsp} |URI of a token endpoint used to obtain a JWT based on the authentication - code. - If not defined, it is obtained from oidcMetadata(Resource), if that is not defined - an attempt is made to use identityUri(URI)/oauth2/v1/token. +code. +If not defined, it is obtained from oidcMetadata(Resource), if that is not defined +an attempt is made to use identityUri(URI)/oauth2/v1/token. |`validate-jwt-with-jwk` |boolean |`true` |Use JWK (a set of keys to validate signatures of JWT) to validate tokens. - Use this method when you want to use default values for JWK or introspection endpoint URI. +Use this method when you want to use default values for JWK or introspection endpoint URI. |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_tracing_Tracer.adoc b/docs/src/main/asciidoc/config/io_helidon_tracing_Tracer.adoc index 60019ba1ad4..0ea887603a7 100644 --- a/docs/src/main/asciidoc/config/io_helidon_tracing_Tracer.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_tracing_Tracer.adoc @@ -1,6 +1,6 @@ /////////////////////////////////////////////////////////////////////////////// - Copyright (c) 2023 Oracle and/or its affiliates. + Copyright (c) 2023, 2024 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. @@ -52,12 +52,33 @@ This is a standalone configuration type, prefix from configuration root: `tracin |`max-queue-size` |int |`2048` |Maximum Queue Size of exporter requests. |`private-key-pem` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Private key in PEM format. |`propagation` |PropagationFormat[] (B3, B3_SINGLE, JAEGER, W3C) |`JAEGER` |Add propagation format to use. + +Allowed values: + +- `B3`: The Zipkin B3 trace context propagation format using multiple headers. +- `B3_SINGLE`: B3 trace context propagation using a single header. +- `JAEGER`: The Jaeger trace context propagation format. +- `W3C`: The W3C trace context propagation format. + |`sampler-param` |Number |`1` |The sampler parameter (number). |`sampler-type` |SamplerType (CONSTANT, RATIO) |`CONSTANT` |Sampler type. - See Sampler types. +See https://www.jaegertracing.io/docs/latest/sampling/#client-sampling-configuration[Sampler types]. + +Allowed values: + +- `CONSTANT`: Constant sampler always makes the same decision for all traces. +It either samples all traces `1` or none of them `0`. +- `RATIO`: Ratio of the requests to sample, double value. + |`schedule-delay` |Duration |`PT5S` |Schedule Delay of exporter requests. |`span-processor-type` |SpanProcessorType (SIMPLE, BATCH) |`batch` |Span Processor type used. + +Allowed values: + +- `SIMPLE`: Simple Span Processor. +- `BATCH`: Batch Span Processor. + |`trusted-cert-pem` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Trusted certificates in PEM format. |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_tracing_providers_jaeger_JaegerTracerBuilder.adoc b/docs/src/main/asciidoc/config/io_helidon_tracing_providers_jaeger_JaegerTracerBuilder.adoc index 60019ba1ad4..0ea887603a7 100644 --- a/docs/src/main/asciidoc/config/io_helidon_tracing_providers_jaeger_JaegerTracerBuilder.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_tracing_providers_jaeger_JaegerTracerBuilder.adoc @@ -1,6 +1,6 @@ /////////////////////////////////////////////////////////////////////////////// - Copyright (c) 2023 Oracle and/or its affiliates. + Copyright (c) 2023, 2024 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. @@ -52,12 +52,33 @@ This is a standalone configuration type, prefix from configuration root: `tracin |`max-queue-size` |int |`2048` |Maximum Queue Size of exporter requests. |`private-key-pem` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Private key in PEM format. |`propagation` |PropagationFormat[] (B3, B3_SINGLE, JAEGER, W3C) |`JAEGER` |Add propagation format to use. + +Allowed values: + +- `B3`: The Zipkin B3 trace context propagation format using multiple headers. +- `B3_SINGLE`: B3 trace context propagation using a single header. +- `JAEGER`: The Jaeger trace context propagation format. +- `W3C`: The W3C trace context propagation format. + |`sampler-param` |Number |`1` |The sampler parameter (number). |`sampler-type` |SamplerType (CONSTANT, RATIO) |`CONSTANT` |Sampler type. - See Sampler types. +See https://www.jaegertracing.io/docs/latest/sampling/#client-sampling-configuration[Sampler types]. + +Allowed values: + +- `CONSTANT`: Constant sampler always makes the same decision for all traces. +It either samples all traces `1` or none of them `0`. +- `RATIO`: Ratio of the requests to sample, double value. + |`schedule-delay` |Duration |`PT5S` |Schedule Delay of exporter requests. |`span-processor-type` |SpanProcessorType (SIMPLE, BATCH) |`batch` |Span Processor type used. + +Allowed values: + +- `SIMPLE`: Simple Span Processor. +- `BATCH`: Batch Span Processor. + |`trusted-cert-pem` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Trusted certificates in PEM format. |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_tracing_providers_zipkin_ZipkinTracerBuilder.adoc b/docs/src/main/asciidoc/config/io_helidon_tracing_providers_zipkin_ZipkinTracerBuilder.adoc index f8e347a05fa..42bed06586c 100644 --- a/docs/src/main/asciidoc/config/io_helidon_tracing_providers_zipkin_ZipkinTracerBuilder.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_tracing_providers_zipkin_ZipkinTracerBuilder.adoc @@ -47,7 +47,13 @@ This is a standalone configuration type, prefix from configuration root: `tracin |key |type |default value |description |`api-version` |Version (V1, V2) |`V2` |Version of Zipkin API to use. - Defaults to Version.V2. +Defaults to Version.V2. + +Allowed values: + +- `V1`: Version 1. +- `V2`: Version 2. + |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webclient_api_HttpClientConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_webclient_api_HttpClientConfig.adoc index 80fc3cff6d5..2cc17d11de9 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webclient_api_HttpClientConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webclient_api_HttpClientConfig.adoc @@ -44,97 +44,97 @@ Type: link:{javadoc-base-url}/io.helidon.webclient.api/io/helidon/webclient/api/ |`base-uri` |ClientUri |{nbsp} |Base uri used by the client in all requests. - Base uri of the client requests +Base uri of the client requests |`connect-timeout` |Duration |{nbsp} |Connect timeout. - Connect timeout - See io.helidon.common.socket.SocketOptions.connectTimeout() +Connect timeout +See io.helidon.common.socket.SocketOptions.connectTimeout() |`connection-cache-size` |int |`256` |Maximal size of the connection cache. - For most HTTP protocols, we may cache connections to various endpoints for keep alive (or stream reuse in case of HTTP/2). - This option limits the size. Setting this number lower than the "usual" number of target services will cause connections - to be closed and reopened frequently. +For most HTTP protocols, we may cache connections to various endpoints for keep alive (or stream reuse in case of HTTP/2). +This option limits the size. Setting this number lower than the "usual" number of target services will cause connections +to be closed and reopened frequently. |`content-encoding` |xref:{rootdir}/config/io_helidon_http_encoding_ContentEncodingContext.adoc[ContentEncodingContext] |{nbsp} |Configure the listener specific io.helidon.http.encoding.ContentEncodingContext. - This method discards all previously registered ContentEncodingContext. - If no content encoding context is registered, default encoding context is used. +This method discards all previously registered ContentEncodingContext. +If no content encoding context is registered, default encoding context is used. - Content encoding context +Content encoding context |`cookie-manager` |xref:{rootdir}/config/io_helidon_webclient_api_WebClientCookieManager.adoc[WebClientCookieManager] |{nbsp} |WebClient cookie manager. - Cookie manager to use +Cookie manager to use |`default-headers` |Map<string, string> |{nbsp} |Default headers to be used in every request from configuration. - Default headers +Default headers |`follow-redirects` |boolean |`true` |Whether to follow redirects. - Whether to follow redirects +Whether to follow redirects |`keep-alive` |boolean |`true` |Determines if connection keep alive is enabled (NOT socket keep alive, but HTTP connection keep alive, to re-use - the same connection for multiple requests). +the same connection for multiple requests). - Keep alive for this connection - See io.helidon.common.socket.SocketOptions.socketKeepAlive() +Keep alive for this connection +See io.helidon.common.socket.SocketOptions.socketKeepAlive() |`max-in-memory-entity` |int |`131072` |If the entity is expected to be smaller that this number of bytes, it would be buffered in memory to optimize performance. - If bigger, streaming will be used. +If bigger, streaming will be used. - Note that for some entity types we cannot use streaming, as they are already fully in memory (String, byte[]), for such - cases, this option is ignored. Default is 128Kb. +Note that for some entity types we cannot use streaming, as they are already fully in memory (String, byte[]), for such +cases, this option is ignored. Default is 128Kb. - Maximal number of bytes to buffer in memory for supported writers +Maximal number of bytes to buffer in memory for supported writers |`max-redirects` |int |`10` |Max number of followed redirects. - This is ignored if followRedirects() option is `false`. +This is ignored if followRedirects() option is `false`. - Max number of followed redirects +Max number of followed redirects |`media-context` |xref:{rootdir}/config/io_helidon_http_media_MediaContext.adoc[MediaContext] |`create()` |Configure the listener specific io.helidon.http.media.MediaContext. - This method discards all previously registered MediaContext. - If no media context is registered, default media context is used. +This method discards all previously registered MediaContext. +If no media context is registered, default media context is used. - Media context -|`media-type-parser-mode` |ParserMode |`ParserMode.STRICT` |Configure media type parsing mode for HTTP `Content-Type` header. +Media context +|`media-type-parser-mode` |ParserMode (STRICT, RELAXED) |`ParserMode.STRICT` |Configure media type parsing mode for HTTP `Content-Type` header. - Media type parsing mode +Media type parsing mode |`properties` |Map<string, string> |{nbsp} |Properties configured for this client. These properties are propagated through client request, to be used by - services (and possibly for other purposes). +services (and possibly for other purposes). - Map of client properties +Map of client properties |`proxy` |xref:{rootdir}/config/io_helidon_webclient_api_Proxy.adoc[Proxy] |{nbsp} |Proxy configuration to be used for requests. - Proxy to use, defaults to Proxy.noProxy() +Proxy to use, defaults to Proxy.noProxy() |`read-continue-timeout` |Duration |`PT1S` |Socket 100-Continue read timeout. Default is 1 second. - This read timeout is used when 100-Continue is sent by the client, before it sends an entity. +This read timeout is used when 100-Continue is sent by the client, before it sends an entity. - Read 100-Continue timeout duration +Read 100-Continue timeout duration |`read-timeout` |Duration |{nbsp} |Read timeout. - Read timeout - See io.helidon.common.socket.SocketOptions.readTimeout() +Read timeout +See io.helidon.common.socket.SocketOptions.readTimeout() |`relative-uris` |boolean |`false` |Can be set to `true` to force the use of relative URIs in all requests, - regardless of the presence or absence of proxies or no-proxy lists. +regardless of the presence or absence of proxies or no-proxy lists. - Relative URIs flag +Relative URIs flag |`send-expect-continue` |boolean |`true` |Whether Expect-100-Continue header is sent to verify server availability before sending an entity. - Defaults to `true`. - +Defaults to `true`. - Whether Expect:100-Continue header should be sent on streamed transfers + +Whether Expect:100-Continue header should be sent on streamed transfers |`services` |io.helidon.webclient.spi.WebClientService[] (service provider interface) |{nbsp} |WebClient services. - Services to use with this web client +Services to use with this web client |`share-connection-cache` |boolean |`true` |Whether to share connection cache between all the WebClient instances in JVM. - True if connection cache is shared +True if connection cache is shared |`socket-options` |xref:{rootdir}/config/io_helidon_common_socket_SocketOptions.adoc[SocketOptions] |{nbsp} |Socket options for connections opened by this client. - If there is a value explicitly configured on this type and on the socket options, - the one configured on this type's builder will win: +If there is a value explicitly configured on this type and on the socket options, +the one configured on this type's builder will win: - readTimeout() - connectTimeout() Socket options |`tls` |xref:{rootdir}/config/io_helidon_common_tls_Tls.adoc[Tls] |{nbsp} |TLS configuration for any TLS request from this client. - TLS can also be configured per request. - TLS is used when the protocol is set to `https`. +TLS can also be configured per request. +TLS is used when the protocol is set to `https`. - TLS configuration to use +TLS configuration to use |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webclient_api_HttpConfigBase.adoc b/docs/src/main/asciidoc/config/io_helidon_webclient_api_HttpConfigBase.adoc index a073af63be0..e111041267e 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webclient_api_HttpConfigBase.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webclient_api_HttpConfigBase.adoc @@ -44,36 +44,36 @@ Type: link:{javadoc-base-url}/io.helidon.webclient.api/io/helidon/webclient/api/ |`connect-timeout` |Duration |{nbsp} |Connect timeout. - Connect timeout - See io.helidon.common.socket.SocketOptions.connectTimeout() +Connect timeout +See io.helidon.common.socket.SocketOptions.connectTimeout() |`follow-redirects` |boolean |`true` |Whether to follow redirects. - Whether to follow redirects +Whether to follow redirects |`keep-alive` |boolean |`true` |Determines if connection keep alive is enabled (NOT socket keep alive, but HTTP connection keep alive, to re-use - the same connection for multiple requests). +the same connection for multiple requests). - Keep alive for this connection - See io.helidon.common.socket.SocketOptions.socketKeepAlive() +Keep alive for this connection +See io.helidon.common.socket.SocketOptions.socketKeepAlive() |`max-redirects` |int |`10` |Max number of followed redirects. - This is ignored if followRedirects() option is `false`. +This is ignored if followRedirects() option is `false`. - Max number of followed redirects +Max number of followed redirects |`properties` |Map<string, string> |{nbsp} |Properties configured for this client. These properties are propagated through client request, to be used by - services (and possibly for other purposes). +services (and possibly for other purposes). - Map of client properties +Map of client properties |`proxy` |xref:{rootdir}/config/io_helidon_webclient_api_Proxy.adoc[Proxy] |{nbsp} |Proxy configuration to be used for requests. - Proxy to use, defaults to Proxy.noProxy() +Proxy to use, defaults to Proxy.noProxy() |`read-timeout` |Duration |{nbsp} |Read timeout. - Read timeout - See io.helidon.common.socket.SocketOptions.readTimeout() +Read timeout +See io.helidon.common.socket.SocketOptions.readTimeout() |`tls` |xref:{rootdir}/config/io_helidon_common_tls_Tls.adoc[Tls] |{nbsp} |TLS configuration for any TLS request from this client. - TLS can also be configured per request. - TLS is used when the protocol is set to `https`. +TLS can also be configured per request. +TLS is used when the protocol is set to `https`. - TLS configuration to use +TLS configuration to use |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webclient_api_Proxy.adoc b/docs/src/main/asciidoc/config/io_helidon_webclient_api_Proxy.adoc index 0ba4f37b433..d475c6b29d6 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webclient_api_Proxy.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webclient_api_Proxy.adoc @@ -1,6 +1,6 @@ /////////////////////////////////////////////////////////////////////////////// - Copyright (c) 2023 Oracle and/or its affiliates. + Copyright (c) 2023, 2024 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. @@ -45,7 +45,7 @@ Type: link:{javadoc-base-url}/io.helidon.webclient.api/io/helidon/webclient/api/ |`host` |string |{nbsp} |Sets a new host value. |`no-proxy` |string[] |{nbsp} |Configure a host pattern that is not going through a proxy. - Options are: +Options are: - IP Address, such as `192.168.1.1` - IP V6 Address, such as `[2001:db8:85a3:8d3:1319:8a2e:370:7348]` @@ -58,6 +58,13 @@ Type: link:{javadoc-base-url}/io.helidon.webclient.api/io/helidon/webclient/api/ |`password` |string |{nbsp} |Sets a new password for the proxy. |`port` |int |{nbsp} |Sets a port value. |`type` |ProxyType (NONE, SYSTEM, HTTP) |`HTTP` |Sets a new proxy type. + +Allowed values: + +- `NONE`: No proxy. +- `SYSTEM`: Proxy obtained from system. +- `HTTP`: HTTP proxy. + |`username` |string |{nbsp} |Sets a new username for the proxy. |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webclient_api_WebClient.adoc b/docs/src/main/asciidoc/config/io_helidon_webclient_api_WebClient.adoc index b00d5d8f6b2..c629ec6c50c 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webclient_api_WebClient.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webclient_api_WebClient.adoc @@ -46,100 +46,100 @@ This is a standalone configuration type, prefix from configuration root: `client |`base-uri` |ClientUri |{nbsp} |Base uri used by the client in all requests. - Base uri of the client requests +Base uri of the client requests |`connect-timeout` |Duration |{nbsp} |Connect timeout. - Connect timeout - See io.helidon.common.socket.SocketOptions.connectTimeout() +Connect timeout +See io.helidon.common.socket.SocketOptions.connectTimeout() |`connection-cache-size` |int |`256` |Maximal size of the connection cache. - For most HTTP protocols, we may cache connections to various endpoints for keep alive (or stream reuse in case of HTTP/2). - This option limits the size. Setting this number lower than the "usual" number of target services will cause connections - to be closed and reopened frequently. +For most HTTP protocols, we may cache connections to various endpoints for keep alive (or stream reuse in case of HTTP/2). +This option limits the size. Setting this number lower than the "usual" number of target services will cause connections +to be closed and reopened frequently. |`content-encoding` |xref:{rootdir}/config/io_helidon_http_encoding_ContentEncodingContext.adoc[ContentEncodingContext] |{nbsp} |Configure the listener specific io.helidon.http.encoding.ContentEncodingContext. - This method discards all previously registered ContentEncodingContext. - If no content encoding context is registered, default encoding context is used. +This method discards all previously registered ContentEncodingContext. +If no content encoding context is registered, default encoding context is used. - Content encoding context +Content encoding context |`cookie-manager` |xref:{rootdir}/config/io_helidon_webclient_api_WebClientCookieManager.adoc[WebClientCookieManager] |{nbsp} |WebClient cookie manager. - Cookie manager to use +Cookie manager to use |`default-headers` |Map<string, string> |{nbsp} |Default headers to be used in every request from configuration. - Default headers +Default headers |`follow-redirects` |boolean |`true` |Whether to follow redirects. - Whether to follow redirects +Whether to follow redirects |`keep-alive` |boolean |`true` |Determines if connection keep alive is enabled (NOT socket keep alive, but HTTP connection keep alive, to re-use - the same connection for multiple requests). +the same connection for multiple requests). - Keep alive for this connection - See io.helidon.common.socket.SocketOptions.socketKeepAlive() +Keep alive for this connection +See io.helidon.common.socket.SocketOptions.socketKeepAlive() |`max-in-memory-entity` |int |`131072` |If the entity is expected to be smaller that this number of bytes, it would be buffered in memory to optimize performance. - If bigger, streaming will be used. +If bigger, streaming will be used. - Note that for some entity types we cannot use streaming, as they are already fully in memory (String, byte[]), for such - cases, this option is ignored. Default is 128Kb. +Note that for some entity types we cannot use streaming, as they are already fully in memory (String, byte[]), for such +cases, this option is ignored. Default is 128Kb. - Maximal number of bytes to buffer in memory for supported writers +Maximal number of bytes to buffer in memory for supported writers |`max-redirects` |int |`10` |Max number of followed redirects. - This is ignored if followRedirects() option is `false`. +This is ignored if followRedirects() option is `false`. - Max number of followed redirects +Max number of followed redirects |`media-context` |xref:{rootdir}/config/io_helidon_http_media_MediaContext.adoc[MediaContext] |`create()` |Configure the listener specific io.helidon.http.media.MediaContext. - This method discards all previously registered MediaContext. - If no media context is registered, default media context is used. +This method discards all previously registered MediaContext. +If no media context is registered, default media context is used. - Media context -|`media-type-parser-mode` |ParserMode |`ParserMode.STRICT` |Configure media type parsing mode for HTTP `Content-Type` header. +Media context +|`media-type-parser-mode` |ParserMode (STRICT, RELAXED) |`ParserMode.STRICT` |Configure media type parsing mode for HTTP `Content-Type` header. - Media type parsing mode +Media type parsing mode |`properties` |Map<string, string> |{nbsp} |Properties configured for this client. These properties are propagated through client request, to be used by - services (and possibly for other purposes). +services (and possibly for other purposes). - Map of client properties +Map of client properties |`protocol-configs` |io.helidon.webclient.spi.ProtocolConfig[] (service provider interface) |{nbsp} |Configuration of client protocols. - Client protocol configurations +Client protocol configurations |`proxy` |xref:{rootdir}/config/io_helidon_webclient_api_Proxy.adoc[Proxy] |{nbsp} |Proxy configuration to be used for requests. - Proxy to use, defaults to Proxy.noProxy() +Proxy to use, defaults to Proxy.noProxy() |`read-continue-timeout` |Duration |`PT1S` |Socket 100-Continue read timeout. Default is 1 second. - This read timeout is used when 100-Continue is sent by the client, before it sends an entity. +This read timeout is used when 100-Continue is sent by the client, before it sends an entity. - Read 100-Continue timeout duration +Read 100-Continue timeout duration |`read-timeout` |Duration |{nbsp} |Read timeout. - Read timeout - See io.helidon.common.socket.SocketOptions.readTimeout() +Read timeout +See io.helidon.common.socket.SocketOptions.readTimeout() |`relative-uris` |boolean |`false` |Can be set to `true` to force the use of relative URIs in all requests, - regardless of the presence or absence of proxies or no-proxy lists. +regardless of the presence or absence of proxies or no-proxy lists. - Relative URIs flag +Relative URIs flag |`send-expect-continue` |boolean |`true` |Whether Expect-100-Continue header is sent to verify server availability before sending an entity. - Defaults to `true`. - +Defaults to `true`. - Whether Expect:100-Continue header should be sent on streamed transfers + +Whether Expect:100-Continue header should be sent on streamed transfers |`services` |io.helidon.webclient.spi.WebClientService[] (service provider interface) |{nbsp} |WebClient services. - Services to use with this web client +Services to use with this web client |`share-connection-cache` |boolean |`true` |Whether to share connection cache between all the WebClient instances in JVM. - True if connection cache is shared +True if connection cache is shared |`socket-options` |xref:{rootdir}/config/io_helidon_common_socket_SocketOptions.adoc[SocketOptions] |{nbsp} |Socket options for connections opened by this client. - If there is a value explicitly configured on this type and on the socket options, - the one configured on this type's builder will win: +If there is a value explicitly configured on this type and on the socket options, +the one configured on this type's builder will win: - readTimeout() - connectTimeout() Socket options |`tls` |xref:{rootdir}/config/io_helidon_common_tls_Tls.adoc[Tls] |{nbsp} |TLS configuration for any TLS request from this client. - TLS can also be configured per request. - TLS is used when the protocol is set to `https`. +TLS can also be configured per request. +TLS is used when the protocol is set to `https`. - TLS configuration to use +TLS configuration to use |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webclient_api_WebClientCookieManager.adoc b/docs/src/main/asciidoc/config/io_helidon_webclient_api_WebClientCookieManager.adoc index 19bf5de5341..7e5c19093f2 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webclient_api_WebClientCookieManager.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webclient_api_WebClientCookieManager.adoc @@ -44,13 +44,13 @@ Type: link:{javadoc-base-url}/io.helidon.webclient.api/io/helidon/webclient/api/ |`automatic-store-enabled` |boolean |`false` |Whether automatic cookie store is enabled or not. - Status of cookie store +Status of cookie store |`cookie-policy` |CookiePolicy |`java.net.CookiePolicy.ACCEPT_ORIGINAL_SERVER` |Current cookie policy for this client. - The cookie policy +The cookie policy |`default-cookies` |Map<string, string> |{nbsp} |Map of default cookies to include in all requests if cookies enabled. - Map of default cookies +Map of default cookies |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webclient_grpc_GrpcClient.adoc b/docs/src/main/asciidoc/config/io_helidon_webclient_grpc_GrpcClient.adoc index 5fc378bd783..f02664d8442 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webclient_grpc_GrpcClient.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webclient_grpc_GrpcClient.adoc @@ -44,7 +44,7 @@ Type: link:{javadoc-base-url}/io.helidon.webclient.grpc/io/helidon/webclient/grp |`protocol-config` |xref:{rootdir}/config/io_helidon_webclient_grpc_GrpcClientProtocolConfig.adoc[GrpcClientProtocolConfig] |`create()` |gRPC specific configuration. - Protocol specific configuration +Protocol specific configuration |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webclient_grpc_GrpcClientProtocolConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_webclient_grpc_GrpcClientProtocolConfig.adoc index b6b42c07985..00a6250c879 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webclient_grpc_GrpcClientProtocolConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webclient_grpc_GrpcClientProtocolConfig.adoc @@ -43,28 +43,28 @@ Type: link:{javadoc-base-url}/io.helidon.webclient.grpc/io/helidon/webclient/grp |key |type |default value |description |`abort-poll-time-expired` |boolean |`false` |Whether to continue retrying after a poll wait timeout expired or not. If a read - operation timeouts out and this flag is set to `false`, the event is logged - and the client will retry. Otherwise, an exception is thrown. +operation timeouts out and this flag is set to `false`, the event is logged +and the client will retry. Otherwise, an exception is thrown. - Abort timeout flag +Abort timeout flag |`heartbeat-period` |Duration |`PT0S` |How often to send a heartbeat (HTTP/2 ping) to check if the connection is still - alive. This is useful for long-running, streaming gRPC calls. It is turned off by - default but can be enabled by setting the period to a value greater than 0. +alive. This is useful for long-running, streaming gRPC calls. It is turned off by +default but can be enabled by setting the period to a value greater than 0. - Heartbeat period +Heartbeat period |`init-buffer-size` |int |`2048` |Initial buffer size used to serialize gRPC request payloads. Buffers shall grow - according to the payload size, but setting this initial buffer size to a larger value - may improve performance for certain applications. +according to the payload size, but setting this initial buffer size to a larger value +may improve performance for certain applications. - Initial buffer size +Initial buffer size |`name` |string |`grpc` |Name identifying this client protocol. Defaults to type. - Name of client protocol +Name of client protocol |`poll-wait-time` |Duration |`PT10S` |How long to wait for the next HTTP/2 data frame to arrive in underlying stream. - Whether this is a fatal error or not is controlled by abortPollTimeExpired(). +Whether this is a fatal error or not is controlled by abortPollTimeExpired(). - Poll time as a duration - See io.helidon.common.socket.SocketOptions.readTimeout() +Poll time as a duration +See io.helidon.common.socket.SocketOptions.readTimeout() |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webclient_http1_Http1ClientProtocolConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_webclient_http1_Http1ClientProtocolConfig.adoc index 8e05c9db49d..e83a2cb8eeb 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webclient_http1_Http1ClientProtocolConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webclient_http1_Http1ClientProtocolConfig.adoc @@ -44,27 +44,27 @@ Type: link:{javadoc-base-url}/io.helidon.webclient.http1/io/helidon/webclient/ht |`default-keep-alive` |boolean |`true` |Whether to use keep alive by default. - `true` for keeping connections alive and re-using them for multiple requests (default), `false` - to create a new connection for each request +`true` for keeping connections alive and re-using them for multiple requests (default), `false` + to create a new connection for each request |`max-header-size` |int |`16384` |Configure the maximum allowed header size of the response. - maximum header size +Maximum header size |`max-status-line-length` |int |`256` |Configure the maximum allowed length of the status line from the response. - Maximum status line length +Maximum status line length |`name` |string |`http_1_1` | |`validate-request-headers` |boolean |`false` |Sets whether the request header format is validated or not. - Defaults to `false` as user has control on the header creation. - + Defaults to `false` as user has control on the header creation. - Whether request header validation should be enabled + +Whether request header validation should be enabled |`validate-response-headers` |boolean |`true` |Sets whether the response header format is validated or not. - Defaults to `true`. - + Defaults to `true`. + - Whether response header validation should be enabled +Whether response header validation should be enabled |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webclient_http2_Http2ClientProtocolConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_webclient_http2_Http2ClientProtocolConfig.adoc index 9e0e74061d0..a5f7112df8b 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webclient_http2_Http2ClientProtocolConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webclient_http2_Http2ClientProtocolConfig.adoc @@ -44,45 +44,49 @@ Type: link:{javadoc-base-url}/io.helidon.webclient.http2/io/helidon/webclient/ht |`flow-control-block-timeout` |Duration |`PT0.1S` |Timeout for blocking between windows size check iterations. - Timeout +Timeout |`initial-window-size` |int |`65535` |Configure INITIAL_WINDOW_SIZE setting for new HTTP/2 connections. - Sends to the server the size of the largest frame payload client is willing to receive. - Defaults to io.helidon.http.http2.WindowSize.DEFAULT_WIN_SIZE. +Sends to the server the size of the largest frame payload client is willing to receive. +Defaults to io.helidon.http.http2.WindowSize.DEFAULT_WIN_SIZE. - Units of octets +Units of octets |`max-frame-size` |int |`16384` |Configure initial MAX_FRAME_SIZE setting for new HTTP/2 connections. - Maximum size of data frames in bytes the client is prepared to accept from the server. - Default value is 2^14(16_384). +Maximum size of data frames in bytes the client is prepared to accept from the server. +Default value is 2^14(16_384). - Data frame size in bytes between 2^14(16_384) and 2^24-1(16_777_215) +Data frame size in bytes between 2^14(16_384) and 2^24-1(16_777_215) |`max-header-list-size` |long |`-1` |Configure initial MAX_HEADER_LIST_SIZE setting for new HTTP/2 connections. - Sends to the server the maximum header field section size client is prepared to accept. - Defaults to `-1`, which means "unconfigured". +Sends to the server the maximum header field section size client is prepared to accept. +Defaults to `-1`, which means "unconfigured". - Units of octets +Units of octets |`name` |string |`h2` | |`ping` |boolean |`false` |Check healthiness of cached connections with HTTP/2.0 ping frame. - Defaults to `false`. +Defaults to `false`. - Use ping if true +Use ping if true |`ping-timeout` |Duration |`PT0.5S` |Timeout for ping probe used for checking healthiness of cached connections. - Defaults to `PT0.5S`, which means 500 milliseconds. +Defaults to `PT0.5S`, which means 500 milliseconds. - Timeout +Timeout |`prior-knowledge` |boolean |`false` |Prior knowledge of HTTP/2 capabilities of the server. If server we are connecting to does not - support HTTP/2 and prior knowledge is set to `false`, only features supported by HTTP/1 will be available - and attempts to use HTTP/2 specific will throw an UnsupportedOperationException. -

      Plain text connection

      - If prior knowledge is set to `true`, we will not attempt an upgrade of connection and use prior knowledge. - If prior knowledge is set to `false`, we will initiate an HTTP/1 connection and upgrade it to HTTP/2, - if supported by the server. - plaintext connection (`h2c`). -

      TLS protected connection

      - If prior knowledge is set to `true`, we will negotiate protocol using HTTP/2 only, failing if not supported. - if prior knowledge is set to `false`, we will negotiate protocol using both HTTP/2 and HTTP/1, using the protocol - supported by server. - - Whether to use prior knowledge of HTTP/2 +support HTTP/2 and prior knowledge is set to `false`, only features supported by HTTP/1 will be available +and attempts to use HTTP/2 specific will throw an UnsupportedOperationException. + +[.underline]#Plain text connection# + +If prior knowledge is set to `true`, we will not attempt an upgrade of connection and use prior knowledge. +If prior knowledge is set to `false`, we will initiate an HTTP/1 connection and upgrade it to HTTP/2, +if supported by the server. +plaintext connection (`h2c`). + +[.underline]#TLS protected connection# + +If prior knowledge is set to `true`, we will negotiate protocol using HTTP/2 only, failing if not supported. +if prior knowledge is set to `false`, we will negotiate protocol using both HTTP/2 and HTTP/1, using the protocol +supported by server. + +Whether to use prior knowledge of HTTP/2 |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webclient_websocket_WsClient.adoc b/docs/src/main/asciidoc/config/io_helidon_webclient_websocket_WsClient.adoc index cde9c2dc9ae..d6a01499062 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webclient_websocket_WsClient.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webclient_websocket_WsClient.adoc @@ -44,7 +44,7 @@ Type: link:{javadoc-base-url}/io.helidon.webclient.websocket/io/helidon/webclien |`protocol-config` |xref:{rootdir}/config/io_helidon_webclient_websocket_WsClientProtocolConfig.adoc[WsClientProtocolConfig] |`create()` |WebSocket specific configuration. - Protocol specific configuration +Protocol specific configuration |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_ConnectionConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_ConnectionConfig.adoc index c2918e61ad4..1f61d668819 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_ConnectionConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webserver_ConnectionConfig.adoc @@ -43,40 +43,40 @@ Type: link:{javadoc-base-url}/io.helidon.webserver/io/helidon/webserver/Connecti |key |type |default value |description |`connect-timeout` |Duration |`PT10S` |Connect timeout. - Default is DEFAULT_CONNECT_TIMEOUT_DURATION. +Default is DEFAULT_CONNECT_TIMEOUT_DURATION. - Connect timeout +Connect timeout |`keep-alive` |boolean |`true` |Configure socket keep alive. - Default is `true`. +Default is `true`. - Keep alive - See java.net.StandardSocketOptions.SO_KEEPALIVE +Keep alive +See java.net.StandardSocketOptions.SO_KEEPALIVE |`read-timeout` |Duration |`PT30S` |Read timeout. - Default is DEFAULT_READ_TIMEOUT_DURATION +Default is DEFAULT_READ_TIMEOUT_DURATION - Read timeout +Read timeout |`receive-buffer-size` |int |`32768` |Socket receive buffer size. - Default is DEFAULT_SO_BUFFER_SIZE. +Default is DEFAULT_SO_BUFFER_SIZE. - Buffer size, in bytes - See java.net.StandardSocketOptions.SO_RCVBUF +Buffer size, in bytes +See java.net.StandardSocketOptions.SO_RCVBUF |`reuse-address` |boolean |`true` |Socket reuse address. - Default is `true`. +Default is `true`. - Whether to reuse address - See java.net.StandardSocketOptions.SO_REUSEADDR +Whether to reuse address +See java.net.StandardSocketOptions.SO_REUSEADDR |`send-buffer-size` |int |`32768` |Socket send buffer size. - Default is DEFAULT_SO_BUFFER_SIZE. +Default is DEFAULT_SO_BUFFER_SIZE. - Buffer size, in bytes - See java.net.StandardSocketOptions.SO_SNDBUF -|`tcp-no-delay` |boolean |`false` |Disable Nagle's algorithm by setting - TCP_NODELAY to true. This can result in better performance on Mac or newer linux kernels for some - payload types. - Default is `false`. +Buffer size, in bytes +See java.net.StandardSocketOptions.SO_SNDBUF +|`tcp-no-delay` |boolean |`false` |Disable https://en.wikipedia.org/wiki/Nagle%27s_algorithm[Nagle's algorithm] by setting +TCP_NODELAY to true. This can result in better performance on Mac or newer linux kernels for some +payload types. +Default is `false`. - Whether to use TCP_NODELAY, defaults to `false` - See java.net.StandardSocketOptions.TCP_NODELAY +Whether to use TCP_NODELAY, defaults to `false` +See java.net.StandardSocketOptions.TCP_NODELAY |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_ListenerConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_ListenerConfig.adoc index a77b8f500ba..d491bf59fa4 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_ListenerConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webserver_ListenerConfig.adoc @@ -44,72 +44,72 @@ Type: link:{javadoc-base-url}/io.helidon.webserver/io/helidon/webserver/Listener |`backlog` |int |`1024` |Accept backlog. - Backlog +Backlog |`connection-config` |xref:{rootdir}/config/io_helidon_webserver_ConnectionConfig.adoc[ConnectionConfig] |{nbsp} |Configuration of a connection (established from client against our server). - Connection configuration +Connection configuration |`connection-options` |xref:{rootdir}/config/io_helidon_common_socket_SocketOptions.adoc[SocketOptions] |{nbsp} |Options for connections accepted by this listener. - This is not used to setup server connection. +This is not used to setup server connection. - Socket options +Socket options |`content-encoding` |xref:{rootdir}/config/io_helidon_http_encoding_ContentEncodingContext.adoc[ContentEncodingContext] |{nbsp} |Configure the listener specific io.helidon.http.encoding.ContentEncodingContext. - This method discards all previously registered ContentEncodingContext. - If no content encoding context is registered, content encoding context of the webserver would be used. +This method discards all previously registered ContentEncodingContext. +If no content encoding context is registered, content encoding context of the webserver would be used. - Content encoding context +Content encoding context |`host` |string |`0.0.0.0` |Host of the default socket. Defaults to all host addresses (`0.0.0.0`). - Host address to listen on (for the default socket) +Host address to listen on (for the default socket) |`idle-connection-period` |Duration |`PT2M` |How often should we check for idleConnectionTimeout(). - Defaults to `PT2M` (2 minutes). +Defaults to `PT2M` (2 minutes). - Period of checking for idle connections +Period of checking for idle connections |`idle-connection-timeout` |Duration |`PT5M` |How long should we wait before closing a connection that has no traffic on it. - Defaults to `PT5M` (5 minutes). Note that the timestamp is refreshed max. once per second, so this setting - would be useless if configured for shorter periods of time (also not a very good support for connection keep alive, - if the connections are killed so soon anyway). +Defaults to `PT5M` (5 minutes). Note that the timestamp is refreshed max. once per second, so this setting +would be useless if configured for shorter periods of time (also not a very good support for connection keep alive, +if the connections are killed so soon anyway). - Timeout of idle connections +Timeout of idle connections |`max-concurrent-requests` |int |`-1` |Limits the number of requests that can be executed at the same time (the number of active virtual threads of requests). - Defaults to `-1`, meaning "unlimited" - what the system allows. - Also make sure that this number is higher than the expected time it takes to handle a single request in your application, - as otherwise you may stop in-progress requests. +Defaults to `-1`, meaning "unlimited" - what the system allows. +Also make sure that this number is higher than the expected time it takes to handle a single request in your application, +as otherwise you may stop in-progress requests. - Number of requests that can be processed on this listener, regardless of protocol +Number of requests that can be processed on this listener, regardless of protocol |`max-in-memory-entity` |int |`131072` |If the entity is expected to be smaller that this number of bytes, it would be buffered in memory to optimize - performance when writing it. - If bigger, streaming will be used. +performance when writing it. +If bigger, streaming will be used. - Note that for some entity types we cannot use streaming, as they are already fully in memory (String, byte[]), for such - cases, this option is ignored. +Note that for some entity types we cannot use streaming, as they are already fully in memory (String, byte[]), for such +cases, this option is ignored. - Default is 128Kb. +Default is 128Kb. - Maximal number of bytes to buffer in memory for supported writers +Maximal number of bytes to buffer in memory for supported writers |`max-payload-size` |long |`-1` |Maximal number of bytes an entity may have. - If io.helidon.http.HeaderNames.CONTENT_LENGTH is used, this is checked immediately, - if io.helidon.http.HeaderValues.TRANSFER_ENCODING_CHUNKED is used, we will fail when the - number of bytes read would exceed the max payload size. - Defaults to unlimited (`-1`). +If io.helidon.http.HeaderNames.CONTENT_LENGTH is used, this is checked immediately, +if io.helidon.http.HeaderValues.TRANSFER_ENCODING_CHUNKED is used, we will fail when the +number of bytes read would exceed the max payload size. +Defaults to unlimited (`-1`). - Maximal number of bytes of entity +Maximal number of bytes of entity |`max-tcp-connections` |int |`-1` |Limits the number of connections that can be opened at a single point in time. - Defaults to `-1`, meaning "unlimited" - what the system allows. +Defaults to `-1`, meaning "unlimited" - what the system allows. - Number of TCP connections that can be opened to this listener, regardless of protocol +Number of TCP connections that can be opened to this listener, regardless of protocol |`media-context` |xref:{rootdir}/config/io_helidon_http_media_MediaContext.adoc[MediaContext] |{nbsp} |Configure the listener specific io.helidon.http.media.MediaContext. - This method discards all previously registered MediaContext. - If no media context is registered, media context of the webserver would be used. +This method discards all previously registered MediaContext. +If no media context is registered, media context of the webserver would be used. - Media context +Media context |`name` |string |`@default` |Name of this socket. Defaults to `@default`. - Must be defined if more than one socket is needed. +Must be defined if more than one socket is needed. - Name of the socket +Name of the socket |`port` |int |`0` |Port of the default socket. - If configured to `0` (the default), server starts on a random port. +If configured to `0` (the default), server starts on a random port. - Port to listen on (for the default socket) +Port to listen on (for the default socket) |`protocols` |io.helidon.webserver.spi.ProtocolConfig[] (service provider interface) Such as: @@ -120,41 +120,45 @@ Such as: - xref:{rootdir}/config/io_helidon_webserver_http1_Http1Config.adoc[http_1_1 (Http1Config)] |{nbsp} |Configuration of protocols. This may be either protocol selectors, or protocol upgraders from HTTP/1.1. - As the order is not important (providers are ordered by weight by default), we can use a configuration as an object, - such as: -
      - protocols:
      -   providers:
      -     http_1_1:
      -       max-prologue-length: 8192
      -     http_2:
      -       max-frame-size: 4096
      -     websocket:
      -       ....
      - 
      - - All defined protocol configurations, loaded from service loader by default +As the order is not important (providers are ordered by weight by default), we can use a configuration as an object, +such as: + +---- + +protocols: + providers: + http_1_1: + max-prologue-length: 8192 + http_2: + max-frame-size: 4096 + websocket: + .... + +---- + + +All defined protocol configurations, loaded from service loader by default |`receive-buffer-size` |int |{nbsp} |Listener receive buffer size. - Buffer size in bytes +Buffer size in bytes |`requested-uri-discovery` |xref:{rootdir}/config/io_helidon_http_RequestedUriDiscoveryContext.adoc[RequestedUriDiscoveryContext] |{nbsp} |Requested URI discovery context. - Discovery context +Discovery context |`shutdown-grace-period` |Duration |`PT0.5S` |Grace period in ISO 8601 duration format to allow running tasks to complete before listener's shutdown. - Default is `500` milliseconds. +Default is `500` milliseconds. Configuration file values example: `PT0.5S`, `PT2S`. - Grace period +Grace period |`tls` |xref:{rootdir}/config/io_helidon_common_tls_Tls.adoc[Tls] |{nbsp} |Listener TLS configuration. - Tls of this configuration +Tls of this configuration |`write-buffer-size` |int |`512` |Initial buffer size in bytes of java.io.BufferedOutputStream created internally to - write data to a socket connection. Default is `512`. +write data to a socket connection. Default is `512`. - Initial buffer size used for writing +Initial buffer size used for writing |`write-queue-length` |int |`0` |Number of buffers queued for write operations. - Maximal number of queued writes, defaults to 0 +Maximal number of queued writes, defaults to 0 |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_WebServer.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_WebServer.adoc index 666d8727631..1053294af48 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_WebServer.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webserver_WebServer.adoc @@ -46,19 +46,19 @@ This is a standalone configuration type, prefix from configuration root: `server |`backlog` |int |`1024` |Accept backlog. - Backlog +Backlog |`connection-config` |xref:{rootdir}/config/io_helidon_webserver_ConnectionConfig.adoc[ConnectionConfig] |{nbsp} |Configuration of a connection (established from client against our server). - Connection configuration +Connection configuration |`connection-options` |xref:{rootdir}/config/io_helidon_common_socket_SocketOptions.adoc[SocketOptions] |{nbsp} |Options for connections accepted by this listener. - This is not used to setup server connection. +This is not used to setup server connection. - Socket options +Socket options |`content-encoding` |xref:{rootdir}/config/io_helidon_http_encoding_ContentEncodingContext.adoc[ContentEncodingContext] |{nbsp} |Configure the listener specific io.helidon.http.encoding.ContentEncodingContext. - This method discards all previously registered ContentEncodingContext. - If no content encoding context is registered, content encoding context of the webserver would be used. +This method discards all previously registered ContentEncodingContext. +If no content encoding context is registered, content encoding context of the webserver would be used. - Content encoding context +Content encoding context |`features` |io.helidon.webserver.spi.ServerFeature[] (service provider interface) Such as: @@ -72,60 +72,60 @@ Such as: |{nbsp} |Server features allow customization of the server, listeners, or routings. - Server features +Server features |`host` |string |`0.0.0.0` |Host of the default socket. Defaults to all host addresses (`0.0.0.0`). - Host address to listen on (for the default socket) +Host address to listen on (for the default socket) |`idle-connection-period` |Duration |`PT2M` |How often should we check for idleConnectionTimeout(). - Defaults to `PT2M` (2 minutes). +Defaults to `PT2M` (2 minutes). - Period of checking for idle connections +Period of checking for idle connections |`idle-connection-timeout` |Duration |`PT5M` |How long should we wait before closing a connection that has no traffic on it. - Defaults to `PT5M` (5 minutes). Note that the timestamp is refreshed max. once per second, so this setting - would be useless if configured for shorter periods of time (also not a very good support for connection keep alive, - if the connections are killed so soon anyway). +Defaults to `PT5M` (5 minutes). Note that the timestamp is refreshed max. once per second, so this setting +would be useless if configured for shorter periods of time (also not a very good support for connection keep alive, +if the connections are killed so soon anyway). - Timeout of idle connections +Timeout of idle connections |`max-concurrent-requests` |int |`-1` |Limits the number of requests that can be executed at the same time (the number of active virtual threads of requests). - Defaults to `-1`, meaning "unlimited" - what the system allows. - Also make sure that this number is higher than the expected time it takes to handle a single request in your application, - as otherwise you may stop in-progress requests. +Defaults to `-1`, meaning "unlimited" - what the system allows. +Also make sure that this number is higher than the expected time it takes to handle a single request in your application, +as otherwise you may stop in-progress requests. - Number of requests that can be processed on this listener, regardless of protocol +Number of requests that can be processed on this listener, regardless of protocol |`max-in-memory-entity` |int |`131072` |If the entity is expected to be smaller that this number of bytes, it would be buffered in memory to optimize - performance when writing it. - If bigger, streaming will be used. +performance when writing it. +If bigger, streaming will be used. - Note that for some entity types we cannot use streaming, as they are already fully in memory (String, byte[]), for such - cases, this option is ignored. +Note that for some entity types we cannot use streaming, as they are already fully in memory (String, byte[]), for such +cases, this option is ignored. - Default is 128Kb. +Default is 128Kb. - Maximal number of bytes to buffer in memory for supported writers +Maximal number of bytes to buffer in memory for supported writers |`max-payload-size` |long |`-1` |Maximal number of bytes an entity may have. - If io.helidon.http.HeaderNames.CONTENT_LENGTH is used, this is checked immediately, - if io.helidon.http.HeaderValues.TRANSFER_ENCODING_CHUNKED is used, we will fail when the - number of bytes read would exceed the max payload size. - Defaults to unlimited (`-1`). +If io.helidon.http.HeaderNames.CONTENT_LENGTH is used, this is checked immediately, +if io.helidon.http.HeaderValues.TRANSFER_ENCODING_CHUNKED is used, we will fail when the +number of bytes read would exceed the max payload size. +Defaults to unlimited (`-1`). - Maximal number of bytes of entity +Maximal number of bytes of entity |`max-tcp-connections` |int |`-1` |Limits the number of connections that can be opened at a single point in time. - Defaults to `-1`, meaning "unlimited" - what the system allows. +Defaults to `-1`, meaning "unlimited" - what the system allows. - Number of TCP connections that can be opened to this listener, regardless of protocol +Number of TCP connections that can be opened to this listener, regardless of protocol |`media-context` |xref:{rootdir}/config/io_helidon_http_media_MediaContext.adoc[MediaContext] |{nbsp} |Configure the listener specific io.helidon.http.media.MediaContext. - This method discards all previously registered MediaContext. - If no media context is registered, media context of the webserver would be used. +This method discards all previously registered MediaContext. +If no media context is registered, media context of the webserver would be used. - Media context +Media context |`name` |string |`@default` |Name of this socket. Defaults to `@default`. - Must be defined if more than one socket is needed. +Must be defined if more than one socket is needed. - Name of the socket +Name of the socket |`port` |int |`0` |Port of the default socket. - If configured to `0` (the default), server starts on a random port. +If configured to `0` (the default), server starts on a random port. - Port to listen on (for the default socket) +Port to listen on (for the default socket) |`protocols` |io.helidon.webserver.spi.ProtocolConfig[] (service provider interface) Such as: @@ -136,51 +136,55 @@ Such as: - xref:{rootdir}/config/io_helidon_webserver_http1_Http1Config.adoc[http_1_1 (Http1Config)] |{nbsp} |Configuration of protocols. This may be either protocol selectors, or protocol upgraders from HTTP/1.1. - As the order is not important (providers are ordered by weight by default), we can use a configuration as an object, - such as: -
      - protocols:
      -   providers:
      -     http_1_1:
      -       max-prologue-length: 8192
      -     http_2:
      -       max-frame-size: 4096
      -     websocket:
      -       ....
      - 
      - - All defined protocol configurations, loaded from service loader by default +As the order is not important (providers are ordered by weight by default), we can use a configuration as an object, +such as: + +---- + +protocols: + providers: + http_1_1: + max-prologue-length: 8192 + http_2: + max-frame-size: 4096 + websocket: + .... + +---- + + +All defined protocol configurations, loaded from service loader by default |`receive-buffer-size` |int |{nbsp} |Listener receive buffer size. - Buffer size in bytes +Buffer size in bytes |`requested-uri-discovery` |xref:{rootdir}/config/io_helidon_http_RequestedUriDiscoveryContext.adoc[RequestedUriDiscoveryContext] |{nbsp} |Requested URI discovery context. - Discovery context +Discovery context |`shutdown-grace-period` |Duration |`PT0.5S` |Grace period in ISO 8601 duration format to allow running tasks to complete before listener's shutdown. - Default is `500` milliseconds. +Default is `500` milliseconds. Configuration file values example: `PT0.5S`, `PT2S`. - Grace period +Grace period |`shutdown-hook` |boolean |`true` |When true the webserver registers a shutdown hook with the JVM Runtime. - Defaults to true. Set this to false such that a shutdown hook is not registered. +Defaults to true. Set this to false such that a shutdown hook is not registered. - Whether to register a shutdown hook +Whether to register a shutdown hook |`sockets` |xref:{rootdir}/config/io_helidon_webserver_ListenerConfig.adoc[Map<string, ListenerConfig>] |{nbsp} |Socket configurations. - Note that socket named WebServer.DEFAULT_SOCKET_NAME cannot be used, - configure the values on the server directly. +Note that socket named WebServer.DEFAULT_SOCKET_NAME cannot be used, +configure the values on the server directly. - Map of listener configurations, except for the default one +Map of listener configurations, except for the default one |`tls` |xref:{rootdir}/config/io_helidon_common_tls_Tls.adoc[Tls] |{nbsp} |Listener TLS configuration. - Tls of this configuration +Tls of this configuration |`write-buffer-size` |int |`512` |Initial buffer size in bytes of java.io.BufferedOutputStream created internally to - write data to a socket connection. Default is `512`. +write data to a socket connection. Default is `512`. - Initial buffer size used for writing +Initial buffer size used for writing |`write-queue-length` |int |`0` |Number of buffers queued for write operations. - Maximal number of queued writes, defaults to 0 +Maximal number of queued writes, defaults to 0 |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_accesslog_AccessLogConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_accesslog_AccessLogConfig.adoc index 56eca6ce309..20f7eac049f 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_accesslog_AccessLogConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webserver_accesslog_AccessLogConfig.adoc @@ -54,79 +54,79 @@ This type provides the following service implementations: |`enabled` |boolean |`true` |Whether this feature will be enabled. - Whether enabled +Whether enabled |`format` |string |{nbsp} |The format for log entries (similar to the Apache `LogFormat`). - + ++++ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      Log format elements
      %hIP address of the remote hostHostLogEntry
      %lThe client identity. This is always undefined in Helidon.UserIdLogEntry
      %uUser ID as asserted by Helidon Security.UserLogEntry
      %tThe timestampTimestampLogEntry
      %rThe request line (`"GET /favicon.ico HTTP/1.0"`)RequestLineLogEntry
      %sThe status code returned to the clientStatusLogEntry
      %bThe entity size in bytesSizeLogEntry
      %DThe time taken in microseconds (start of request until last byte written)TimeTakenLogEntry
      %TThe time taken in seconds (start of request until last byte written), integerTimeTakenLogEntry
      %{header-name}iValue of header `header-name`HeaderLogEntry
      + Log format elements + + %h + IP address of the remote host + HostLogEntry + + + %l + The client identity. This is always undefined in Helidon. + UserIdLogEntry + + + %u + User ID as asserted by Helidon Security. + UserLogEntry + + + %t + The timestamp + TimestampLogEntry + + + %r + The request line (`"GET /favicon.ico HTTP/1.0"`) + RequestLineLogEntry + + + %s + The status code returned to the client + StatusLogEntry + + + %b + The entity size in bytes + SizeLogEntry + + + %D + The time taken in microseconds (start of request until last byte written) + TimeTakenLogEntry + + + %T + The time taken in seconds (start of request until last byte written), integer + TimeTakenLogEntry + + + %{header-name}i + Value of header `header-name` + HeaderLogEntry + + ++++ - Format string, such as `%h %l %u %t %r %b %{Referer`i} +Format string, such as `%h %l %u %t %r %b %{Referer`i} |`logger-name` |string |`io.helidon.webserver.AccessLog` |Name of the logger used to obtain access log logger from System.getLogger(String). - Defaults to AccessLogFeature.DEFAULT_LOGGER_NAME. +Defaults to AccessLogFeature.DEFAULT_LOGGER_NAME. - Name of the logger to use +Name of the logger to use |`sockets` |string[] |{nbsp} |List of sockets to register this feature on. If empty, it would get registered on all sockets. - The logger used will have the expected logger with a suffix of the socket name. +The logger used will have the expected logger with a suffix of the socket name. - Socket names to register on, defaults to empty (all available sockets) +Socket names to register on, defaults to empty (all available sockets) |`weight` |double |`1000.0` |Weight of the access log feature. We need to log access for anything happening on the server, so weight is high: - io.helidon.webserver.accesslog.AccessLogFeature.WEIGHT. +io.helidon.webserver.accesslog.AccessLogFeature.WEIGHT. - Weight of the feature +Weight of the feature |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_accesslog_AccessLogFeature.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_accesslog_AccessLogFeature.adoc index 56eca6ce309..20f7eac049f 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_accesslog_AccessLogFeature.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webserver_accesslog_AccessLogFeature.adoc @@ -54,79 +54,79 @@ This type provides the following service implementations: |`enabled` |boolean |`true` |Whether this feature will be enabled. - Whether enabled +Whether enabled |`format` |string |{nbsp} |The format for log entries (similar to the Apache `LogFormat`). - + ++++ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      Log format elements
      %hIP address of the remote hostHostLogEntry
      %lThe client identity. This is always undefined in Helidon.UserIdLogEntry
      %uUser ID as asserted by Helidon Security.UserLogEntry
      %tThe timestampTimestampLogEntry
      %rThe request line (`"GET /favicon.ico HTTP/1.0"`)RequestLineLogEntry
      %sThe status code returned to the clientStatusLogEntry
      %bThe entity size in bytesSizeLogEntry
      %DThe time taken in microseconds (start of request until last byte written)TimeTakenLogEntry
      %TThe time taken in seconds (start of request until last byte written), integerTimeTakenLogEntry
      %{header-name}iValue of header `header-name`HeaderLogEntry
      + Log format elements + + %h + IP address of the remote host + HostLogEntry + + + %l + The client identity. This is always undefined in Helidon. + UserIdLogEntry + + + %u + User ID as asserted by Helidon Security. + UserLogEntry + + + %t + The timestamp + TimestampLogEntry + + + %r + The request line (`"GET /favicon.ico HTTP/1.0"`) + RequestLineLogEntry + + + %s + The status code returned to the client + StatusLogEntry + + + %b + The entity size in bytes + SizeLogEntry + + + %D + The time taken in microseconds (start of request until last byte written) + TimeTakenLogEntry + + + %T + The time taken in seconds (start of request until last byte written), integer + TimeTakenLogEntry + + + %{header-name}i + Value of header `header-name` + HeaderLogEntry + + ++++ - Format string, such as `%h %l %u %t %r %b %{Referer`i} +Format string, such as `%h %l %u %t %r %b %{Referer`i} |`logger-name` |string |`io.helidon.webserver.AccessLog` |Name of the logger used to obtain access log logger from System.getLogger(String). - Defaults to AccessLogFeature.DEFAULT_LOGGER_NAME. +Defaults to AccessLogFeature.DEFAULT_LOGGER_NAME. - Name of the logger to use +Name of the logger to use |`sockets` |string[] |{nbsp} |List of sockets to register this feature on. If empty, it would get registered on all sockets. - The logger used will have the expected logger with a suffix of the socket name. +The logger used will have the expected logger with a suffix of the socket name. - Socket names to register on, defaults to empty (all available sockets) +Socket names to register on, defaults to empty (all available sockets) |`weight` |double |`1000.0` |Weight of the access log feature. We need to log access for anything happening on the server, so weight is high: - io.helidon.webserver.accesslog.AccessLogFeature.WEIGHT. +io.helidon.webserver.accesslog.AccessLogFeature.WEIGHT. - Weight of the feature +Weight of the feature |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_context_ContextFeature.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_context_ContextFeature.adoc index 47a1a21772a..9af38b286ed 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_context_ContextFeature.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webserver_context_ContextFeature.adoc @@ -54,11 +54,11 @@ This type provides the following service implementations: |`sockets` |string[] |{nbsp} |List of sockets to register this feature on. If empty, it would get registered on all sockets. - Socket names to register on, defaults to empty (all available sockets) +Socket names to register on, defaults to empty (all available sockets) |`weight` |double |`1100.0` |Weight of the context feature. As it is used by other features, the default is quite high: - io.helidon.webserver.context.ContextFeature.WEIGHT. +io.helidon.webserver.context.ContextFeature.WEIGHT. - Weight of the feature +Weight of the feature |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_cors_CorsConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_cors_CorsConfig.adoc index c57c843420d..ee25c9fcf1e 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_cors_CorsConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webserver_cors_CorsConfig.adoc @@ -51,7 +51,7 @@ This type provides the following service implementations: |`enabled` |boolean |{nbsp} |This feature can be disabled. - Whether the feature is enabled +Whether the feature is enabled |=== @@ -65,11 +65,11 @@ This type provides the following service implementations: |`sockets` |string[] |{nbsp} |List of sockets to register this feature on. If empty, it would get registered on all sockets. - Socket names to register on, defaults to empty (all available sockets) +Socket names to register on, defaults to empty (all available sockets) |`weight` |double |`850.0` |Weight of the CORS feature. As it is used by other features, the default is quite high: - CorsFeature.WEIGHT. +CorsFeature.WEIGHT. - Weight of the feature +Weight of the feature |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_cors_CorsFeature.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_cors_CorsFeature.adoc index c57c843420d..ee25c9fcf1e 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_cors_CorsFeature.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webserver_cors_CorsFeature.adoc @@ -51,7 +51,7 @@ This type provides the following service implementations: |`enabled` |boolean |{nbsp} |This feature can be disabled. - Whether the feature is enabled +Whether the feature is enabled |=== @@ -65,11 +65,11 @@ This type provides the following service implementations: |`sockets` |string[] |{nbsp} |List of sockets to register this feature on. If empty, it would get registered on all sockets. - Socket names to register on, defaults to empty (all available sockets) +Socket names to register on, defaults to empty (all available sockets) |`weight` |double |`850.0` |Weight of the CORS feature. As it is used by other features, the default is quite high: - CorsFeature.WEIGHT. +CorsFeature.WEIGHT. - Weight of the feature +Weight of the feature |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_metrics_api_ComponentMetricsSettings_Builder.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_grpc_GrpcTracingConfig.adoc similarity index 63% rename from docs/src/main/asciidoc/config/io_helidon_metrics_api_ComponentMetricsSettings_Builder.adoc rename to docs/src/main/asciidoc/config/io_helidon_webserver_grpc_GrpcTracingConfig.adoc index 7fb5649a7df..3bfc5e60bf7 100644 --- a/docs/src/main/asciidoc/config/io_helidon_metrics_api_ComponentMetricsSettings_Builder.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webserver_grpc_GrpcTracingConfig.adoc @@ -17,25 +17,19 @@ /////////////////////////////////////////////////////////////////////////////// ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.metrics.api.ComponentMetricsSettings.Builder -:keywords: helidon, config, io.helidon.metrics.api.ComponentMetricsSettings.Builder -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.metrics.api.ComponentMetricsSettings.Builder +:description: Configuration of io.helidon.webserver.grpc.GrpcTracingConfig +:keywords: helidon, config, io.helidon.webserver.grpc.GrpcTracingConfig +:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.grpc.GrpcTracingConfig include::{rootdir}/includes/attributes.adoc[] -= Builder (metrics.api.ComponentMetricsSettings) Configuration += GrpcTracingConfig (webserver.grpc) Configuration // tag::config[] -Type: link:{javadoc-base-url}/io.helidon.metrics.api.ComponentMetricsSettings/io/helidon/metrics/api/ComponentMetricsSettings/Builder.html[io.helidon.metrics.api.ComponentMetricsSettings.Builder] +Type: link:{javadoc-base-url}/io.helidon.webserver.grpc/io/helidon/webserver/grpc/GrpcTracingConfig.html[io.helidon.webserver.grpc.GrpcTracingConfig] -[source,text] -.Config key ----- -metrics ----- - == Configuration options @@ -48,7 +42,9 @@ metrics |=== |key |type |default value |description -|`enabled` |boolean |{nbsp} |Sets whether metrics should be enabled for the component. +|`enabled` |boolean |`true` |A flag indicating if tracing is enabled. +|`streaming` |boolean |`false` |A flag indicating streaming logging. +|`verbose` |boolean |`false` |A flag indicating verbose logging. |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_http1_Http1Config.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_http1_Http1Config.adoc index a72c8fbf80c..dfbd09abf48 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_http1_Http1Config.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webserver_http1_Http1Config.adoc @@ -53,49 +53,49 @@ This type provides the following service implementations: |key |type |default value |description |`continue-immediately` |boolean |`false` |When true WebServer answers to expect continue with 100 continue immediately, - not waiting for user to actually request the data. +not waiting for user to actually request the data. - If `true` answer with 100 continue immediately after expect continue +If `true` answer with 100 continue immediately after expect continue |`max-headers-size` |int |`16384` |Maximal size of received headers in bytes. - Maximal header size -|`max-prologue-length` |int |`2048` |Maximal size of received HTTP prologue (GET /path HTTP/1.1). +Maximal header size +|`max-prologue-length` |int |`4096` |Maximal size of received HTTP prologue (GET /path HTTP/1.1). - Maximal size in bytes +Maximal size in bytes |`recv-log` |boolean |`true` |Logging of received packets. Uses trace and debug levels on logger of - Http1LoggingConnectionListener with suffix of `.recv``. +Http1LoggingConnectionListener with suffix of `.recv``. - `true` if logging should be enabled for received packets, `false` if no logging should be done +`true` if logging should be enabled for received packets, `false` if no logging should be done |`requested-uri-discovery` |xref:{rootdir}/config/io_helidon_http_RequestedUriDiscoveryContext.adoc[RequestedUriDiscoveryContext] |{nbsp} |Requested URI discovery settings. - Settings for computing the requested URI +Settings for computing the requested URI |`send-log` |boolean |`true` |Logging of sent packets. Uses trace and debug levels on logger of - Http1LoggingConnectionListener with suffix of `.send``. +Http1LoggingConnectionListener with suffix of `.send``. - `true` if logging should be enabled for sent packets, `false` if no logging should be done +`true` if logging should be enabled for sent packets, `false` if no logging should be done |`validate-path` |boolean |`true` |If set to false, any path is accepted (even containing illegal characters). - Whether to validate path +Whether to validate path |`validate-request-headers` |boolean |`true` |Whether to validate headers. - If set to false, any value is accepted, otherwise validates headers + known headers - are validated by format - (content length is always validated as it is part of protocol processing (other headers may be validated if - features use them)). +If set to false, any value is accepted, otherwise validates headers + known headers +are validated by format +(content length is always validated as it is part of protocol processing (other headers may be validated if +features use them)). - Defaults to `true`. - + Defaults to `true`. - Whether to validate headers + +Whether to validate headers |`validate-response-headers` |boolean |`false` |Whether to validate headers. - If set to false, any value is accepted, otherwise validates headers + known headers - are validated by format - (content length is always validated as it is part of protocol processing (other headers may be validated if - features use them)). +If set to false, any value is accepted, otherwise validates headers + known headers +are validated by format +(content length is always validated as it is part of protocol processing (other headers may be validated if +features use them)). + + Defaults to `false` as user has control on the header creation. - Defaults to `false` as user has control on the header creation. - - Whether to validate headers +Whether to validate headers |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_http2_Http2Config.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_http2_Http2Config.adoc index bb471c1a91b..fd1e8bee832 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_http2_Http2Config.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webserver_http2_Http2Config.adoc @@ -53,75 +53,75 @@ This type provides the following service implementations: |key |type |default value |description |`flow-control-timeout` |Duration |`PT0.1S` |Outbound flow control blocking timeout configured as java.time.Duration - or text in ISO-8601 format. - Blocking timeout defines an interval to wait for the outbound window size changes(incoming window updates) - before the next blocking iteration. - Default value is `PT0.1S`. +or text in ISO-8601 format. +Blocking timeout defines an interval to wait for the outbound window size changes(incoming window updates) +before the next blocking iteration. +Default value is `PT0.1S`. + - ++++ - - - - -
      ISO_8601 format examples:
      PT0.1S100 milliseconds
      PT0.5S500 milliseconds
      PT2S2 seconds
      + *ISO_8601 format examples:* + PT0.1S100 milliseconds + PT0.5S500 milliseconds + PT2S2 seconds + ++++ - Duration - See ISO_8601 Durations +Duration +See https://en.wikipedia.org/wiki/ISO_8601.Durations[ISO_8601 Durations] |`initial-window-size` |int |`1048576` |This setting indicates the sender's maximum window size in bytes for stream-level flow control. - Default and maximum value is 231-1 = 2147483647 bytes. This setting affects the window size - of HTTP/2 connection. - Any value greater than 2147483647 causes an error. Any value smaller than initial window size causes an error. - See RFC 9113 section 6.9.1 for details. +Default and maximum value is 2^31^-1 = 2147483647 bytes. This setting affects the window size +of HTTP/2 connection. +Any value greater than 2147483647 causes an error. Any value smaller than initial window size causes an error. +See RFC 9113 section 6.9.1 for details. - Maximum window size in bytes +Maximum window size in bytes |`max-concurrent-streams` |long |`8192` |Maximum number of concurrent streams that the server will allow. - Defaults to `8192`. This limit is directional: it applies to the number of streams that the sender - permits the receiver to create. - It is recommended that this value be no smaller than 100 to not unnecessarily limit parallelism - See RFC 9113 section 6.5.2 for details. +Defaults to `8192`. This limit is directional: it applies to the number of streams that the sender +permits the receiver to create. +It is recommended that this value be no smaller than 100 to not unnecessarily limit parallelism +See RFC 9113 section 6.5.2 for details. - Maximal number of concurrent streams +Maximal number of concurrent streams |`max-empty-frames` |int |`10` |Maximum number of consecutive empty frames allowed on connection. - Max number of consecutive empty frames +Max number of consecutive empty frames |`max-frame-size` |int |`16384` |The size of the largest frame payload that the sender is willing to receive in bytes. - Default value is `16384` and maximum value is 224-1 = 16777215 bytes. - See RFC 9113 section 6.5.2 for details. +Default value is `16384` and maximum value is 2^24^-1 = 16777215 bytes. +See RFC 9113 section 6.5.2 for details. - Maximal frame size +Maximal frame size |`max-header-list-size` |long |`8192` |The maximum field section size that the sender is prepared to accept in bytes. - See RFC 9113 section 6.5.2 for details. - Default is 8192. +See RFC 9113 section 6.5.2 for details. +Default is 8192. - Maximal header list size in bytes +Maximal header list size in bytes |`max-rapid-resets` |int |`100` |Maximum number of rapid resets(stream RST sent by client before any data have been sent by server). - When reached within rapidResetCheckPeriod(), GOAWAY is sent to client and connection is closed. - Default value is `100`. +When reached within rapidResetCheckPeriod(), GOAWAY is sent to client and connection is closed. +Default value is `100`. - Maximum number of rapid resets - See CVE-2023-44487 +Maximum number of rapid resets +See https://nvd.nist.gov/vuln/detail/CVE-2023-44487[CVE-2023-44487] |`rapid-reset-check-period` |Duration |`PT10S` |Period for counting rapid resets(stream RST sent by client before any data have been sent by server). - Default value is `PT10S`. +Default value is `PT10S`. - Duration - See CVE-2023-44487 - See ISO_8601 Durations +Duration +See https://nvd.nist.gov/vuln/detail/CVE-2023-44487[CVE-2023-44487] +See https://en.wikipedia.org/wiki/ISO_8601.Durations[ISO_8601 Durations] |`requested-uri-discovery` |xref:{rootdir}/config/io_helidon_http_RequestedUriDiscoveryContext.adoc[RequestedUriDiscoveryContext] |{nbsp} |Requested URI discovery settings. - Settings for computing the requested URI +Settings for computing the requested URI |`send-error-details` |boolean |`false` |Whether to send error message over HTTP to client. - Defaults to `false`, as exception message may contain internal information that could be used as an - attack vector. Use with care and in cases where both server and clients are under your full control (such as for - testing). +Defaults to `false`, as exception message may contain internal information that could be used as an +attack vector. Use with care and in cases where both server and clients are under your full control (such as for +testing). - Whether to send error messages over the network +Whether to send error messages over the network |`validate-path` |boolean |`true` |If set to false, any path is accepted (even containing illegal characters). - Whether to validate path +Whether to validate path |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_ObserveFeature.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_observe_ObserveFeature.adoc index 2559f02848a..5244d9fc584 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_ObserveFeature.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webserver_observe_ObserveFeature.adoc @@ -54,18 +54,18 @@ This type provides the following service implementations: |`cors` |xref:{rootdir}/config/io_helidon_cors_CrossOriginConfig.adoc[CrossOriginConfig] |`@io.helidon.cors.CrossOriginConfig@.create()` |Cors support inherited by each observe provider, unless explicitly configured. - Cors support to use +Cors support to use |`enabled` |boolean |`true` |Whether the observe support is enabled. - `false` to disable observe feature +`false` to disable observe feature |`endpoint` |string |`/observe` |Root endpoint to use for observe providers. By default, all observe endpoint are under this root endpoint. - Example: -
      - If root endpoint is `/observe` (the default), and default health endpoint is `health` (relative), - health endpoint would be `/observe/health`. +Example: - Endpoint to use +If root endpoint is `/observe` (the default), and default health endpoint is `health` (relative), +health endpoint would be `/observe/health`. + +Endpoint to use |`observers` |io.helidon.webserver.observe.spi.Observer[] (service provider interface) Such as: @@ -78,18 +78,18 @@ Such as: - xref:{rootdir}/config/io_helidon_webserver_observe_health_HealthObserver.adoc[health (HealthObserver)] |{nbsp} |Observers to use with this observe features. - Each observer type is registered only once, unless it uses a custom name (default name is the same as the type). +Each observer type is registered only once, unless it uses a custom name (default name is the same as the type). - List of observers to use in this feature +List of observers to use in this feature |`sockets` |string[] |{nbsp} |Sockets the observability endpoint should be exposed on. If not defined, defaults to the default socket - (io.helidon.webserver.WebServer.DEFAULT_SOCKET_NAME. - Each observer may have its own configuration of sockets that are relevant to it, this only controls the endpoints! +(io.helidon.webserver.WebServer.DEFAULT_SOCKET_NAME. +Each observer may have its own configuration of sockets that are relevant to it, this only controls the endpoints! - List of sockets to register observe endpoint on +List of sockets to register observe endpoint on |`weight` |double |`80.0` |Change the weight of this feature. This may change the order of registration of this feature. - By default, observability weight is ObserveFeature.WEIGHT so it is registered after routing. +By default, observability weight is ObserveFeature.WEIGHT so it is registered after routing. - Weight to use +Weight to use |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_ObserverConfigBase.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_observe_ObserverConfigBase.adoc index 2419abb5a7c..36a34c8816e 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_ObserverConfigBase.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webserver_observe_ObserverConfigBase.adoc @@ -44,7 +44,7 @@ Type: link:{javadoc-base-url}/io.helidon.webserver.observe/io/helidon/webserver/ |`enabled` |boolean |`true` |Whether this observer is enabled. - `false` to disable observer +`false` to disable observer |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_config_ConfigObserver.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_observe_config_ConfigObserver.adoc index ed70f806692..1fb7e003355 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_config_ConfigObserver.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webserver_observe_config_ConfigObserver.adoc @@ -55,11 +55,11 @@ This type provides the following service implementations: |`endpoint` |string |`config` | |`permit-all` |boolean |{nbsp} |Permit all access, even when not authorized. - Whether to permit access for anybody +Whether to permit access for anybody |`secrets` |string[] |`.*password, .*passphrase, .*secret` |Secret patterns (regular expressions) to exclude from output. - Any pattern that matches a key will cause the output to be obfuscated and not contain the value. +Any pattern that matches a key will cause the output to be obfuscated and not contain the value. - Patterns always added: +Patterns always added: - `.*password` - `.*passphrase` diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_health_HealthObserver.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_observe_health_HealthObserver.adoc index 6af7c2322a1..a90b9b1a25e 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_health_HealthObserver.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webserver_observe_health_HealthObserver.adoc @@ -49,19 +49,19 @@ This type provides the following service implementations: |key |type |default value |description |`details` |boolean |`false` |Whether details should be printed. - By default, health only returns a io.helidon.http.Status.NO_CONTENT_204 for success, - io.helidon.http.Status.SERVICE_UNAVAILABLE_503 for health down, - and io.helidon.http.Status.INTERNAL_SERVER_ERROR_500 in case of error with no entity. - When details are enabled, health returns io.helidon.http.Status.OK_200 for success, same codes - otherwise - and a JSON entity with detailed information about each health check executed. - - Set to `true` to enable details +By default, health only returns a io.helidon.http.Status.NO_CONTENT_204 for success, +io.helidon.http.Status.SERVICE_UNAVAILABLE_503 for health down, +and io.helidon.http.Status.INTERNAL_SERVER_ERROR_500 in case of error with no entity. +When details are enabled, health returns io.helidon.http.Status.OK_200 for success, same codes +otherwise +and a JSON entity with detailed information about each health check executed. + +Set to `true` to enable details |`endpoint` |string |`health` | |`use-system-services` |boolean |`true` |Whether to use services discovered by java.util.ServiceLoader. - By default, all io.helidon.health.spi.HealthCheckProvider based health checks are added. +By default, all io.helidon.health.spi.HealthCheckProvider based health checks are added. - Set to `false` to disable discovery +Set to `false` to disable discovery |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_info_InfoObserver.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_observe_info_InfoObserver.adoc index e56c148a15a..6872c65ac7d 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_info_InfoObserver.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webserver_observe_info_InfoObserver.adoc @@ -55,7 +55,7 @@ This type provides the following service implementations: |`endpoint` |string |`info` | |`values` |Map<string, string> |{nbsp} |Values to be exposed using this observability endpoint. - Value map +Value map |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_log_LogObserver.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_observe_log_LogObserver.adoc index ff1d897bf07..d025673dd62 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_log_LogObserver.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webserver_observe_log_LogObserver.adoc @@ -55,10 +55,10 @@ This type provides the following service implementations: |`endpoint` |string |`log` | |`permit-all` |boolean |{nbsp} |Permit all access, even when not authorized. - Whether to permit access for anybody +Whether to permit access for anybody |`stream` |xref:{rootdir}/config/io_helidon_webserver_observe_log_LogStreamConfig.adoc[LogStreamConfig] |`@io.helidon.webserver.observe.log.LogStreamConfig@.create()` |Configuration of log stream. - Log stream configuration +Log stream configuration |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_log_LogStreamConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_observe_log_LogStreamConfig.adoc index 8d1c4ecd18a..bdfbe38769d 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_log_LogStreamConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webserver_observe_log_LogStreamConfig.adoc @@ -45,20 +45,20 @@ Type: link:{javadoc-base-url}/io.helidon.webserver.observe.log/io/helidon/webser |`content-type` |HttpMediaType |`@io.helidon.http.HttpMediaTypes@.PLAINTEXT_UTF_8` | |`enabled` |boolean |`true` |Whether stream is enabled. - Whether to allow streaming of log statements +Whether to allow streaming of log statements |`idle-message-timeout` |Duration |`PT5S` |How long to wait before we send the idle message, to make sure we keep the stream alive. - If no messages appear within this duration, and idle message will be sent - See idleString() +If no messages appear within this duration, and idle message will be sent +See idleString() |`idle-string` |string |`% ` |String sent when there are no log messages within the idleMessageTimeout(). - String to write over the network when no log messages are received +String to write over the network when no log messages are received |`queue-size` |int |`100` |Length of the in-memory queue that buffers log messages from loggers before sending them over the network. - If the messages are produced faster than we can send them to client, excess messages are DISCARDED, and will not - be sent. +If the messages are produced faster than we can send them to client, excess messages are DISCARDED, and will not +be sent. - Size of the in-memory queue for log messages +Size of the in-memory queue for log messages |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_metrics_MetricsObserver.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_observe_metrics_MetricsObserver.adoc index c46b8bd9267..6f968b52e26 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_metrics_MetricsObserver.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webserver_observe_metrics_MetricsObserver.adoc @@ -50,33 +50,47 @@ This type provides the following service implementations: |`app-name` |string |{nbsp} |Value for the application tag to be added to each meter ID. - Application tag value +Application tag value |`app-tag-name` |string |{nbsp} |Name for the application tag to be added to each meter ID. - Application tag name +Application tag name |`enabled` |boolean |`true` |Whether metrics functionality is enabled. - If metrics are configured to be enabled +If metrics are configured to be enabled |`endpoint` |string |`metrics` | +|[.line-through]#`gc-time-type`# |GcTimeType (GAUGE, COUNTER) |`GcTimeType.COUNTER` |*Deprecated* Whether the `gc.time` meter should be registered as a gauge (vs. a counter). +The `gc.time` meter is inspired by the MicroProfile Metrics spec, in which the meter was originally checked to +be a counter but starting in 5.1 was checked be a gauge. For the duration of Helidon 4.x users can choose which +type of meter Helidon registers for `gc.time`. +The type of meter to use for registering `gc.time` +@deprecated Provided for backward compatibility only; no replacement + +Allowed values: + +- `GAUGE`: Implement the meter as a gauge. This is backward-incompatible with Helidon 4.0.x releases but complies with +MicroProfile 5.1. +- `COUNTER`: Implement the meter as a counter. This is backward-compatible with Helidon 4.0.x releases but does not comply with +MicroProfile 5.1. + |`key-performance-indicators` |xref:{rootdir}/config/io_helidon_metrics_api_KeyPerformanceIndicatorMetricsConfig.adoc[KeyPerformanceIndicatorMetricsConfig] |{nbsp} |Key performance indicator metrics settings. - Key performance indicator metrics settings +Key performance indicator metrics settings |`permit-all` |boolean |`true` |Whether to allow anybody to access the endpoint. - Whether to permit access to metrics endpoint to anybody, defaults to `true` - See roles() -|`rest-request-enabled` |boolean |{nbsp} |Whether automatic REST request metrics should be measured. +Whether to permit access to metrics endpoint to anybody, defaults to `true` +See roles() +|`rest-request-enabled` |boolean |`false` |Whether automatic REST request metrics should be measured. - True/false +True/false |`roles` |string[] |`observe` |Hints for role names the user is expected to be in. - List of hints +List of hints |`scoping` |xref:{rootdir}/config/io_helidon_metrics_api_ScopingConfig.adoc[ScopingConfig] |{nbsp} |Settings related to scoping management. - Scoping settings +Scoping settings |`tags` |xref:{rootdir}/config/io_helidon_metrics_api_Tag.adoc[Tag[]] |{nbsp} |Global tags. - Name/value pairs for global tags +Name/value pairs for global tags |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_tracing_TracingObserver.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_observe_tracing_TracingObserver.adoc index feea2ca6abc..a20fec9e836 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_tracing_TracingObserver.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webserver_observe_tracing_TracingObserver.adoc @@ -54,7 +54,7 @@ This type provides the following service implementations: |`env-config` |TracingConfig |`TracingConfig.ENABLED` |Use the provided configuration as a default for any request. - Default web server tracing configuration +Default web server tracing configuration |`paths` |PathTracingConfig[] |`new @java.util.ArrayList@(@java.util.List@.of(PathTracingConfig.builder() .path("/metrics/*") .tracingConfig(TracingConfig.DISABLED) @@ -80,12 +80,12 @@ This type provides the following service implementations: .tracingConfig(TracingConfig.DISABLED) .build()))` |Path specific configuration of tracing. - Configuration of tracing for specific paths +Configuration of tracing for specific paths |`weight` |double |`900.0` |Weight of the feature registered with WebServer. - Changing weight may cause tracing to be executed at a different time (such as after security, or even after - all routes). Please understand feature weights before changing this order. +Changing weight may cause tracing to be executed at a different time (such as after security, or even after +all routes). Please understand feature weights before changing this order. - Weight of tracing feature +Weight of tracing feature |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_security_PathsConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_security_PathsConfig.adoc index c8edd4ef024..b653473b436 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_security_PathsConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webserver_security_PathsConfig.adoc @@ -44,45 +44,45 @@ Type: link:{javadoc-base-url}/io.helidon.webserver.security/io/helidon/webserver |`audit` |boolean |{nbsp} |Whether to audit this request - defaults to false, if enabled, request is audited with event type "request". - Whether to audit +Whether to audit |`audit-event-type` |string |{nbsp} |Override for event-type, defaults to SecurityHandler.DEFAULT_AUDIT_EVENT_TYPE. - Audit event type to use +Audit event type to use |`audit-message-format` |string |{nbsp} |Override for audit message format, defaults to SecurityHandler.DEFAULT_AUDIT_MESSAGE_FORMAT. - Audit message format to use +Audit message format to use |`authenticate` |boolean |{nbsp} |If called, request will go through authentication process - defaults to false (even if authorize is true). - Whether to authenticate or not +Whether to authenticate or not |`authentication-optional` |boolean |{nbsp} |If called, authentication failure will not abort request and will continue as anonymous (defaults to false). - Whether authn is optional +Whether authn is optional |`authenticator` |string |{nbsp} |Use a named authenticator (as supported by security - if not defined, default authenticator is used). - Will enable authentication. +Will enable authentication. - Name of authenticator as configured in io.helidon.security.Security +Name of authenticator as configured in io.helidon.security.Security |`authorize` |boolean |{nbsp} |Enable authorization for this route. - Whether to authorize +Whether to authorize |`authorizer` |string |{nbsp} |Use a named authorizer (as supported by security - if not defined, default authorizer is used, if none defined, all is - permitted). - Will enable authorization. +permitted). +Will enable authorization. - Name of authorizer as configured in io.helidon.security.Security +Name of authorizer as configured in io.helidon.security.Security |`methods` |Method[] |{nbsp} | |`path` |string |{nbsp} | |`roles-allowed` |string[] |{nbsp} |An array of allowed roles for this path - must have a security provider supporting roles (either authentication - or authorization provider). - This method enables authentication and authorization (you can disable them again by calling - SecurityHandler.skipAuthorization() - and authenticationOptional() if needed). +or authorization provider). +This method enables authentication and authorization (you can disable them again by calling +SecurityHandler.skipAuthorization() +and authenticationOptional() if needed). - If subject is any of these roles, allow access +If subject is any of these roles, allow access |`sockets` |string[] |`@default` | |`sockets` |string[] |{nbsp} |List of sockets this configuration should be applied to. - If empty, the configuration is applied to all configured sockets. +If empty, the configuration is applied to all configured sockets. - List of sockets +List of sockets |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_security_SecurityFeature.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_security_SecurityFeature.adoc index 4b294500092..ae75399478c 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_security_SecurityFeature.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webserver_security_SecurityFeature.adoc @@ -54,22 +54,22 @@ This type provides the following service implementations: |`defaults` |xref:{rootdir}/config/io_helidon_webserver_security_SecurityHandler.adoc[SecurityHandler] |`SecurityHandler.create()` |The default security handler. - Security handler defaults +Security handler defaults |`paths` |xref:{rootdir}/config/io_helidon_webserver_security_PathsConfig.adoc[PathsConfig[]] |{nbsp} |Configuration for webserver paths. - Path configuration +Path configuration |`security` |xref:{rootdir}/config/io_helidon_security_Security.adoc[Security] |{nbsp} |Security associated with this feature. - If not specified here, the feature uses security registered with - io.helidon.common.context.Contexts.globalContext(), if not found, it creates a new - instance from root of configuration (using `security` key). +If not specified here, the feature uses security registered with +io.helidon.common.context.Contexts.globalContext(), if not found, it creates a new +instance from root of configuration (using `security` key). - This configuration allows usage of a different security instance for a specific security feature setup. +This configuration allows usage of a different security instance for a specific security feature setup. - Security instance to be used to handle security in this feature configuration +Security instance to be used to handle security in this feature configuration |`weight` |double |`800.0` |Weight of the security feature. Value is: - io.helidon.webserver.security.SecurityFeature.WEIGHT. +io.helidon.webserver.security.SecurityFeature.WEIGHT. - Weight of the feature +Weight of the feature |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_security_SecurityHandler.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_security_SecurityHandler.adoc index 413683d1227..24e592fb2bb 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_security_SecurityHandler.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webserver_security_SecurityHandler.adoc @@ -44,42 +44,42 @@ Type: link:{javadoc-base-url}/io.helidon.webserver.security/io/helidon/webserver |`audit` |boolean |{nbsp} |Whether to audit this request - defaults to false, if enabled, request is audited with event type "request". - Whether to audit +Whether to audit |`audit-event-type` |string |{nbsp} |Override for event-type, defaults to SecurityHandler.DEFAULT_AUDIT_EVENT_TYPE. - Audit event type to use +Audit event type to use |`audit-message-format` |string |{nbsp} |Override for audit message format, defaults to SecurityHandler.DEFAULT_AUDIT_MESSAGE_FORMAT. - Audit message format to use +Audit message format to use |`authenticate` |boolean |{nbsp} |If called, request will go through authentication process - defaults to false (even if authorize is true). - Whether to authenticate or not +Whether to authenticate or not |`authentication-optional` |boolean |{nbsp} |If called, authentication failure will not abort request and will continue as anonymous (defaults to false). - Whether authn is optional +Whether authn is optional |`authenticator` |string |{nbsp} |Use a named authenticator (as supported by security - if not defined, default authenticator is used). - Will enable authentication. +Will enable authentication. - Name of authenticator as configured in io.helidon.security.Security +Name of authenticator as configured in io.helidon.security.Security |`authorize` |boolean |{nbsp} |Enable authorization for this route. - Whether to authorize +Whether to authorize |`authorizer` |string |{nbsp} |Use a named authorizer (as supported by security - if not defined, default authorizer is used, if none defined, all is - permitted). - Will enable authorization. +permitted). +Will enable authorization. - Name of authorizer as configured in io.helidon.security.Security +Name of authorizer as configured in io.helidon.security.Security |`roles-allowed` |string[] |{nbsp} |An array of allowed roles for this path - must have a security provider supporting roles (either authentication - or authorization provider). - This method enables authentication and authorization (you can disable them again by calling - SecurityHandler.skipAuthorization() - and authenticationOptional() if needed). +or authorization provider). +This method enables authentication and authorization (you can disable them again by calling +SecurityHandler.skipAuthorization() +and authenticationOptional() if needed). - If subject is any of these roles, allow access +If subject is any of these roles, allow access |`sockets` |string[] |{nbsp} |List of sockets this configuration should be applied to. - If empty, the configuration is applied to all configured sockets. +If empty, the configuration is applied to all configured sockets. - List of sockets +List of sockets |=== diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_websocket_WsConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_websocket_WsConfig.adoc index 304bd316def..f5f49945de5 100644 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_websocket_WsConfig.adoc +++ b/docs/src/main/asciidoc/config/io_helidon_webserver_websocket_WsConfig.adoc @@ -53,15 +53,15 @@ This type provides the following service implementations: |key |type |default value |description |`max-frame-length` |int |`1048576` |Max WebSocket frame size supported by the server on a read operation. - Default is 1 MB. +Default is 1 MB. - Max frame size to read +Max frame size to read |`name` |string |`websocket` |Name of this configuration. - Configuration name +Configuration name |`origins` |string[] |{nbsp} |WebSocket origins. - Origins +Origins |=== diff --git a/docs/src/main/asciidoc/config/io_opentracing_Tracer.adoc b/docs/src/main/asciidoc/config/io_opentracing_Tracer.adoc index f8e347a05fa..42bed06586c 100644 --- a/docs/src/main/asciidoc/config/io_opentracing_Tracer.adoc +++ b/docs/src/main/asciidoc/config/io_opentracing_Tracer.adoc @@ -47,7 +47,13 @@ This is a standalone configuration type, prefix from configuration root: `tracin |key |type |default value |description |`api-version` |Version (V1, V2) |`V2` |Version of Zipkin API to use. - Defaults to Version.V2. +Defaults to Version.V2. + +Allowed values: + +- `V1`: Version 1. +- `V2`: Version 2. + |=== diff --git a/docs/src/main/asciidoc/mp/jwt.adoc b/docs/src/main/asciidoc/mp/jwt.adoc index 9bd621144c7..6b28fcae36c 100644 --- a/docs/src/main/asciidoc/mp/jwt.adoc +++ b/docs/src/main/asciidoc/mp/jwt.adoc @@ -77,7 +77,7 @@ The following interfaces and annotations are used to work with JWT in Helidon MP == Configuration -include::{rootdir}/config/io_helidon_microprofile_jwt.adoc[leveloffset=+1,tag=config] +include::{rootdir}/config/io_helidon_microprofile_jwt_auth_JwtAuthProvider.adoc[leveloffset=+1,tag=config] A configuration example in `microprofile-config.properties`: [source, properties] diff --git a/fault-tolerance/fault-tolerance/pom.xml b/fault-tolerance/fault-tolerance/pom.xml index 56d8ffd184a..39e8f42b20e 100644 --- a/fault-tolerance/fault-tolerance/pom.xml +++ b/fault-tolerance/fault-tolerance/pom.xml @@ -91,8 +91,8 @@ ${helidon.version}
      - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} @@ -114,8 +114,8 @@ - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} diff --git a/http/encoding/encoding/pom.xml b/http/encoding/encoding/pom.xml index 268542fb9ce..92208be8691 100644 --- a/http/encoding/encoding/pom.xml +++ b/http/encoding/encoding/pom.xml @@ -80,8 +80,8 @@ ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} @@ -103,8 +103,8 @@ - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} diff --git a/http/http/pom.xml b/http/http/pom.xml index e013cf91f10..24157668137 100644 --- a/http/http/pom.xml +++ b/http/http/pom.xml @@ -100,16 +100,26 @@ - io.helidon.config - helidon-config-metadata-processor + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} diff --git a/http/media/media/pom.xml b/http/media/media/pom.xml index 8627bf155e1..337f321f8c3 100644 --- a/http/media/media/pom.xml +++ b/http/media/media/pom.xml @@ -78,8 +78,8 @@ ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} @@ -106,8 +106,8 @@ ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} diff --git a/integrations/micrometer/micrometer/pom.xml b/integrations/micrometer/micrometer/pom.xml index e3bcdd04110..e496c5dc9ed 100644 --- a/integrations/micrometer/micrometer/pom.xml +++ b/integrations/micrometer/micrometer/pom.xml @@ -93,11 +93,6 @@ helidon-config-metadata true - - io.helidon.config - helidon-config-metadata-processor - true - org.junit.jupiter junit-jupiter-api @@ -125,18 +120,40 @@ -Xlint:-requires-automatic + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + io.helidon.common.features helidon-common-features-processor ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} + + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.common.features + helidon-common-features-processor + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen + ${helidon.version} + + diff --git a/integrations/neo4j/neo4j/pom.xml b/integrations/neo4j/neo4j/pom.xml index e76c111eccc..b1eca13ba98 100644 --- a/integrations/neo4j/neo4j/pom.xml +++ b/integrations/neo4j/neo4j/pom.xml @@ -67,18 +67,40 @@ maven-compiler-plugin + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + io.helidon.common.features helidon-common-features-processor ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} + + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.common.features + helidon-common-features-processor + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen + ${helidon.version} + + diff --git a/integrations/oci/metrics/metrics/pom.xml b/integrations/oci/metrics/metrics/pom.xml index 33f634d462a..3ce96c3abd4 100644 --- a/integrations/oci/metrics/metrics/pom.xml +++ b/integrations/oci/metrics/metrics/pom.xml @@ -80,16 +80,26 @@ - io.helidon.config - helidon-config-metadata-processor + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} diff --git a/integrations/oci/oci/pom.xml b/integrations/oci/oci/pom.xml index 2c34dfd312f..ced67f7c12b 100644 --- a/integrations/oci/oci/pom.xml +++ b/integrations/oci/oci/pom.xml @@ -128,8 +128,8 @@ ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} @@ -156,8 +156,8 @@ ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} diff --git a/integrations/oci/tls-certificates/pom.xml b/integrations/oci/tls-certificates/pom.xml index 2b53e02903c..da9f580880e 100644 --- a/integrations/oci/tls-certificates/pom.xml +++ b/integrations/oci/tls-certificates/pom.xml @@ -140,8 +140,8 @@ ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} @@ -168,8 +168,8 @@ ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} diff --git a/integrations/openapi-ui/pom.xml b/integrations/openapi-ui/pom.xml index e90e5367ee3..eac0f1ab174 100644 --- a/integrations/openapi-ui/pom.xml +++ b/integrations/openapi-ui/pom.xml @@ -86,8 +86,8 @@ ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} @@ -114,8 +114,8 @@ ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} diff --git a/integrations/vault/auths/approle/pom.xml b/integrations/vault/auths/approle/pom.xml index cd31ed2272c..d3af08ca900 100644 --- a/integrations/vault/auths/approle/pom.xml +++ b/integrations/vault/auths/approle/pom.xml @@ -74,8 +74,8 @@ ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} diff --git a/lra/coordinator/server/pom.xml b/lra/coordinator/server/pom.xml index cfedfd763fa..0c801defe74 100644 --- a/lra/coordinator/server/pom.xml +++ b/lra/coordinator/server/pom.xml @@ -111,6 +111,7 @@ org.slf4j slf4j-jdk14 + runtime io.helidon.webserver.testing.junit5 diff --git a/metrics/api/pom.xml b/metrics/api/pom.xml index eaef22a1010..0f0d4a86372 100644 --- a/metrics/api/pom.xml +++ b/metrics/api/pom.xml @@ -97,8 +97,8 @@ ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} @@ -125,8 +125,8 @@ ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} diff --git a/microprofile/jwt-auth/pom.xml b/microprofile/jwt-auth/pom.xml index f8e3ad829bf..faf7b10dea6 100644 --- a/microprofile/jwt-auth/pom.xml +++ b/microprofile/jwt-auth/pom.xml @@ -72,6 +72,11 @@ helidon-common-features-api true + + io.helidon.config + helidon-config-metadata + true + jakarta.interceptor jakarta.interceptor-api @@ -106,6 +111,16 @@ maven-compiler-plugin + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen + ${helidon.version} + io.helidon.common.features helidon-common-features-processor @@ -113,6 +128,23 @@ + + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen + ${helidon.version} + + + io.helidon.common.features + helidon-common-features-processor + ${helidon.version} + + diff --git a/microprofile/jwt-auth/src/main/java/io/helidon/microprofile/jwt/auth/JwtAuthProvider.java b/microprofile/jwt-auth/src/main/java/io/helidon/microprofile/jwt/auth/JwtAuthProvider.java index 4daa1767a86..26457fe0721 100644 --- a/microprofile/jwt-auth/src/main/java/io/helidon/microprofile/jwt/auth/JwtAuthProvider.java +++ b/microprofile/jwt-auth/src/main/java/io/helidon/microprofile/jwt/auth/JwtAuthProvider.java @@ -56,6 +56,9 @@ import io.helidon.common.config.Config; import io.helidon.common.configurable.Resource; import io.helidon.common.pki.Keys; +import io.helidon.config.metadata.Configured; +import io.helidon.config.metadata.ConfiguredOption; +import io.helidon.config.metadata.ConfiguredValue; import io.helidon.http.HeaderNames; import io.helidon.security.AuthenticationResponse; import io.helidon.security.EndpointConfig; @@ -608,7 +611,11 @@ private void update(Jwt.Builder builder) { /** * Fluent API builder for {@link JwtAuthProvider}. */ + @Configured(description = "MP-JWT Auth configuration is defined by the spec (options prefixed with `mp.jwt.`), " + + "and we add a few configuration options for the security provider (options prefixed with " + + "`security.providers.mp-jwt-auth.`)") public static class Builder implements io.helidon.common.Builder { + private static final String HELIDON_CONFIG_PREFIX = "security.providers.mp-jwt-auth."; private static final String CONFIG_PUBLIC_KEY = "mp.jwt.verify.publickey"; private static final String CONFIG_PUBLIC_KEY_PATH = "mp.jwt.verify.publickey.location"; private static final String CONFIG_JWT_DECRYPT_KEY_LOCATION = "mp.jwt.decrypt.key.location"; @@ -945,6 +952,7 @@ private JwkKeys loadPublicKeyJWK(String jwkJson) { * @param propagate whether to propagate identity (true) or not (false) * @return updated builder instance */ + @ConfiguredOption(key = HELIDON_CONFIG_PREFIX + "propagate", value = "true") public Builder propagate(boolean propagate) { this.propagate = propagate; return this; @@ -956,6 +964,7 @@ public Builder propagate(boolean propagate) { * @param authenticate whether to authenticate (true) or not (false) * @return updated builder instance */ + @ConfiguredOption(key = HELIDON_CONFIG_PREFIX + "authenticate", value = "true") public Builder authenticate(boolean authenticate) { this.authenticate = authenticate; return this; @@ -970,6 +979,7 @@ public Builder authenticate(boolean authenticate) { * @param allowImpersonation set to true to allow impersonation * @return updated builder instance */ + @ConfiguredOption(key = HELIDON_CONFIG_PREFIX + "allow-impersonation", value = "false") public Builder allowImpersonation(boolean allowImpersonation) { this.allowImpersonation = allowImpersonation; return this; @@ -981,6 +991,7 @@ public Builder allowImpersonation(boolean allowImpersonation) { * @param subjectType type of principal * @return updated builder instance */ + @ConfiguredOption(key = HELIDON_CONFIG_PREFIX + "principal-type", value = "USER") public Builder subjectType(SubjectType subjectType) { this.subjectType = subjectType; @@ -997,10 +1008,12 @@ public Builder subjectType(SubjectType subjectType) { /** * Token handler to extract username from request. + * Uses {@code Authorization} header with {@code bearer } prefix by default. * * @param tokenHandler token handler instance * @return updated builder instance */ + @ConfiguredOption(key = HELIDON_CONFIG_PREFIX + "atn-token.handler") public Builder atnTokenHandler(TokenHandler tokenHandler) { this.atnTokenHandler = tokenHandler; @@ -1015,6 +1028,7 @@ public Builder atnTokenHandler(TokenHandler tokenHandler) { * @param optional whether authentication is optional (true) or required (false) * @return updated builder instance */ + @ConfiguredOption(key = HELIDON_CONFIG_PREFIX + "optional", value = "false") public Builder optional(boolean optional) { this.optional = optional; return this; @@ -1027,6 +1041,7 @@ public Builder optional(boolean optional) { * to add our configuration. * @return updated builder instance */ + @ConfiguredOption(key = HELIDON_CONFIG_PREFIX + "sign-token") public Builder outboundConfig(OutboundConfig config) { this.outboundConfig = config; return this; @@ -1071,6 +1086,7 @@ public Builder issuer(String issuer) { * @param publicKey String representation * @return updated builder instance */ + @ConfiguredOption(key = CONFIG_PUBLIC_KEY) public Builder publicKey(String publicKey) { // from MP specification - if defined, get rid of publicKeyPath from Helidon Config, // as we must fail if both are defined using MP configuration options @@ -1081,10 +1097,13 @@ public Builder publicKey(String publicKey) { /** * Path to public key. + * The value may be a relative path or a URL. * * @param publicKeyPath Public key path * @return updated builder instance */ + @ConfiguredOption(key = CONFIG_PUBLIC_KEY_PATH) + @ConfiguredOption(key = HELIDON_CONFIG_PREFIX + "atn-token.verify-key") public Builder publicKeyPath(String publicKeyPath) { this.publicKeyPath = publicKeyPath; return this; @@ -1107,6 +1126,7 @@ public Builder defaultJwk(Jwk defaultJwk) { * @param defaultKeyId Default JWT key ID * @return updated builder instance */ + @ConfiguredOption(key = HELIDON_CONFIG_PREFIX + "atn-token.default-key-id") public Builder defaultKeyId(String defaultKeyId) { this.defaultKeyId = defaultKeyId; return this; @@ -1118,6 +1138,9 @@ public Builder defaultKeyId(String defaultKeyId) { * @param config configuration to load from * @return updated builder instance */ + @ConfiguredOption(key = HELIDON_CONFIG_PREFIX + "atn-token.jwk.resource", + type = Resource.class, + description = "JWK resource for authenticating the request") public Builder config(Config config) { config.get("optional").asBoolean().ifPresent(this::optional); config.get("authenticate").asBoolean().ifPresent(this::authenticate); @@ -1162,9 +1185,12 @@ public Builder config(Config config) { } /** + * Name of the header expected to contain the token. + * * @param header header name which should be used * @return updated builder instance */ + @ConfiguredOption(key = CONFIG_JWT_HEADER, value = "Authorization") public Builder jwtHeader(String header) { if (HeaderNames.COOKIE.defaultCase().equalsIgnoreCase(header)) { useCookie = true; @@ -1184,6 +1210,7 @@ public Builder jwtHeader(String header) { * @param cookieProperty cookie property name * @return updated builder instance */ + @ConfiguredOption(key = CONFIG_COOKIE_PROPERTY_NAME, value = "Bearer") public Builder cookieProperty(String cookieProperty) { this.cookieProperty = cookieProperty; return this; @@ -1195,6 +1222,7 @@ public Builder cookieProperty(String cookieProperty) { * @param issuer name of issuer * @return updated builder instance */ + @ConfiguredOption(key = CONFIG_EXPECTED_ISSUER) public Builder expectedIssuer(String issuer) { this.expectedIssuer = issuer; return this; @@ -1208,6 +1236,7 @@ public Builder expectedIssuer(String issuer) { * @deprecated use {@link #addExpectedAudience(String)} instead */ @Deprecated(forRemoval = true, since = "2.4.0") + @ConfiguredOption(key = HELIDON_CONFIG_PREFIX + "atn-token.jwt-audience") public Builder expectedAudience(String audience) { return addExpectedAudience(audience); } @@ -1224,11 +1253,14 @@ public Builder addExpectedAudience(String audience) { } /** - * Replace expected audiences with the content of the provided collection. + * Expected audiences of incoming tokens. * * @param audiences expected audiences to use * @return updated builder instance */ + @ConfiguredOption(key = CONFIG_EXPECTED_AUDIENCES, + type = String.class, + kind = ConfiguredOption.Kind.LIST) public Builder expectedAudiences(Collection audiences) { this.expectedAudiences.clear(); this.expectedAudiences.addAll(audiences); @@ -1236,33 +1268,41 @@ public Builder expectedAudiences(Collection audiences) { } /** - * Maximal expected token age. If this value is set, {@code iat} claim needs to be present in the JWT. + * Maximal expected token age in seconds. If this value is set, {@code iat} claim needs to be present in the JWT. * * @param expectedMaxTokenAge expected maximal token age in seconds * @return updated builder instance */ + @ConfiguredOption(key = CONFIG_EXPECTED_MAX_TOKEN_AGE) public Builder expectedMaxTokenAge(int expectedMaxTokenAge) { this.expectedMaxTokenAge = Duration.ofSeconds(expectedMaxTokenAge); return this; } /** - * Private key to decryption of encrypted claims. + * Private key for decryption of encrypted claims. + * The value may be a relative path or a URL. * * @param decryptKeyLocation private key location * @return updated builder instance */ + @ConfiguredOption(key = CONFIG_JWT_DECRYPT_KEY_LOCATION) public Builder decryptKeyLocation(String decryptKeyLocation) { this.decryptKeyLocation = decryptKeyLocation; return this; } /** - * Expected decryption key algorithm. + * Expected key management algorithm supported by the MP JWT endpoint. + * Supported algorithms are either {@code RSA-OAEP} or {@code RSA-OAEP-256}. + * If no algorithm is set, both algorithms must be accepted. * * @param decryptionKeyAlgorithm expected decryption key algorithm * @return updated builder instance */ + @ConfiguredOption(key = CONFIG_JWT_DECRYPT_KEY_ALGORITHM, + allowedValues = {@ConfiguredValue(value = "RSA-OAEP", description = "RSA-OAEP Algorithm"), + @ConfiguredValue(value = "RSA-OAEP-256", description = "RSA-OAEP-256 Algorithm")}) public Builder decryptKeyAlgorithm(String decryptionKeyAlgorithm) { this.decryptionKeyAlgorithm = decryptionKeyAlgorithm; return this; @@ -1275,17 +1315,19 @@ public Builder decryptKeyAlgorithm(String decryptionKeyAlgorithm) { * @param loadOnStartup load verification keys on server startup * @return updated builder instance */ + @ConfiguredOption(key = HELIDON_CONFIG_PREFIX + "load-on-startup", value = "false") public Builder loadOnStartup(boolean loadOnStartup) { this.loadOnStartup = loadOnStartup; return this; } /** - * Clock skew to be accounted for in token expiration and max age validations. + * Clock skew to be accounted for in token expiration and max age validations in seconds. * * @param clockSkew clock skew * @return updated builder instance */ + @ConfiguredOption(key = CONFIG_CLOCK_SKEW, value = "5") public Builder clockSkew(int clockSkew) { this.clockSkew = Duration.ofSeconds(clockSkew); return this; diff --git a/microprofile/jwt-auth/src/main/java/module-info.java b/microprofile/jwt-auth/src/main/java/module-info.java index f6707f0a5b4..220f4a5bfcd 100644 --- a/microprofile/jwt-auth/src/main/java/module-info.java +++ b/microprofile/jwt-auth/src/main/java/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023 Oracle and/or its affiliates. + * Copyright (c) 2018, 2024 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. @@ -43,6 +43,7 @@ requires microprofile.jwt.auth.api; requires static io.helidon.common.features.api; + requires static io.helidon.config.metadata; requires transitive io.helidon.config; requires transitive io.helidon.security.jwt; diff --git a/microprofile/lra/jax-rs/pom.xml b/microprofile/lra/jax-rs/pom.xml index a463007a48e..d1676e48b8c 100644 --- a/microprofile/lra/jax-rs/pom.xml +++ b/microprofile/lra/jax-rs/pom.xml @@ -111,6 +111,11 @@ maven-compiler-plugin + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + io.helidon.common.features helidon-common-features-processor @@ -118,6 +123,18 @@ + + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.common.features + helidon-common-features-processor + ${helidon.version} + + diff --git a/microprofile/openapi/pom.xml b/microprofile/openapi/pom.xml index 65a26ec1aa3..0adf9f47f46 100644 --- a/microprofile/openapi/pom.xml +++ b/microprofile/openapi/pom.xml @@ -100,11 +100,6 @@ helidon-common-features-api true - - io.helidon.config - helidon-config-metadata-processor - true - jakarta.interceptor jakarta.interceptor-api @@ -196,8 +191,8 @@ ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} @@ -224,8 +219,8 @@ ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} diff --git a/microprofile/server/pom.xml b/microprofile/server/pom.xml index 73b33048e5e..43bc7a6e93c 100644 --- a/microprofile/server/pom.xml +++ b/microprofile/server/pom.xml @@ -37,11 +37,6 @@ - - io.helidon.config - helidon-config-metadata-processor - true - io.helidon.config helidon-config-metadata @@ -175,18 +170,40 @@ maven-compiler-plugin + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + io.helidon.common.features helidon-common-features-processor ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} + + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.common.features + helidon-common-features-processor + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen + ${helidon.version} + + diff --git a/openapi/openapi/pom.xml b/openapi/openapi/pom.xml index 9edaad70a5d..1b016979bea 100644 --- a/openapi/openapi/pom.xml +++ b/openapi/openapi/pom.xml @@ -110,8 +110,8 @@ ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} @@ -138,8 +138,8 @@ ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} diff --git a/scheduling/pom.xml b/scheduling/pom.xml index e05c3c588b0..1461040a9df 100644 --- a/scheduling/pom.xml +++ b/scheduling/pom.xml @@ -80,41 +80,56 @@ - io.helidon.common.features - helidon-common-features-processor + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.common.features + helidon-common-features-processor ${helidon.version} io.helidon.builder - helidon-builder-processor + helidon-builder-codegen ${helidon.version} - io.helidon.common.processor - helidon-common-processor-helidon-copyright + io.helidon.codegen + helidon-codegen-helidon-copyright ${helidon.version} - io.helidon.builder - helidon-builder-processor + io.helidon.codegen + helidon-codegen-apt ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen + ${helidon.version} + + + io.helidon.common.features + helidon-common-features-processor + ${helidon.version} + + + io.helidon.builder + helidon-builder-codegen ${helidon.version} - io.helidon.common.processor - helidon-common-processor-helidon-copyright + io.helidon.codegen + helidon-codegen-helidon-copyright ${helidon.version} diff --git a/security/providers/abac/pom.xml b/security/providers/abac/pom.xml index 671352d313b..eb906e2e798 100644 --- a/security/providers/abac/pom.xml +++ b/security/providers/abac/pom.xml @@ -52,11 +52,6 @@ helidon-config-metadata true - - io.helidon.config - helidon-config-metadata-processor - true - org.junit.jupiter junit-jupiter-api @@ -81,22 +76,32 @@ maven-compiler-plugin + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + io.helidon.common.features helidon-common-features-processor ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} diff --git a/security/providers/common/pom.xml b/security/providers/common/pom.xml index f546c916b68..9a70ea9df1b 100644 --- a/security/providers/common/pom.xml +++ b/security/providers/common/pom.xml @@ -73,16 +73,26 @@ - io.helidon.config - helidon-config-metadata-processor + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} diff --git a/security/providers/config-vault/pom.xml b/security/providers/config-vault/pom.xml index 1f5714191df..113153474e1 100644 --- a/security/providers/config-vault/pom.xml +++ b/security/providers/config-vault/pom.xml @@ -59,11 +59,6 @@ helidon-config-metadata true - - io.helidon.config - helidon-config-metadata-processor - true - io.helidon.bundles helidon-bundles-config @@ -88,6 +83,16 @@ maven-compiler-plugin + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen + ${helidon.version} + io.helidon.common.features helidon-common-features-processor @@ -95,6 +100,23 @@ + + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen + ${helidon.version} + + + io.helidon.common.features + helidon-common-features-processor + ${helidon.version} + + diff --git a/security/providers/google-login/pom.xml b/security/providers/google-login/pom.xml index 8417bb2c56f..ee0ba444c41 100644 --- a/security/providers/google-login/pom.xml +++ b/security/providers/google-login/pom.xml @@ -63,11 +63,6 @@ helidon-config-metadata true - - io.helidon.config - helidon-config-metadata-processor - true - io.helidon.config helidon-config-encryption @@ -102,18 +97,40 @@ maven-compiler-plugin + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + io.helidon.common.features helidon-common-features-processor ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} + + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.common.features + helidon-common-features-processor + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen + ${helidon.version} + + diff --git a/security/providers/header/pom.xml b/security/providers/header/pom.xml index 06db66e1e63..ff9fde5dd51 100644 --- a/security/providers/header/pom.xml +++ b/security/providers/header/pom.xml @@ -48,11 +48,6 @@ helidon-config-metadata true - - io.helidon.config - helidon-config-metadata-processor - true - io.helidon.config helidon-config-encryption @@ -87,18 +82,40 @@ maven-compiler-plugin + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + io.helidon.common.features helidon-common-features-processor ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} + + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.common.features + helidon-common-features-processor + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen + ${helidon.version} + + diff --git a/security/providers/http-auth/pom.xml b/security/providers/http-auth/pom.xml index 3357a2f096d..9b5a7643187 100644 --- a/security/providers/http-auth/pom.xml +++ b/security/providers/http-auth/pom.xml @@ -56,11 +56,6 @@ helidon-config-metadata true - - io.helidon.config - helidon-config-metadata-processor - true - org.glassfish.jersey.inject jersey-hk2 @@ -120,18 +115,40 @@ maven-compiler-plugin + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + io.helidon.common.features helidon-common-features-processor ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} + + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.common.features + helidon-common-features-processor + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen + ${helidon.version} + + diff --git a/security/providers/http-sign/pom.xml b/security/providers/http-sign/pom.xml index 173cc90b286..c03bf298b61 100644 --- a/security/providers/http-sign/pom.xml +++ b/security/providers/http-sign/pom.xml @@ -56,11 +56,6 @@ helidon-config-metadata true - - io.helidon.config - helidon-config-metadata-processor - true - org.glassfish.jersey.inject jersey-hk2 @@ -105,18 +100,40 @@ maven-compiler-plugin + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + io.helidon.common.features helidon-common-features-processor ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} + + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.common.features + helidon-common-features-processor + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen + ${helidon.version} + + diff --git a/security/providers/idcs-mapper/pom.xml b/security/providers/idcs-mapper/pom.xml index 3c848a3555b..3e2041ccff6 100644 --- a/security/providers/idcs-mapper/pom.xml +++ b/security/providers/idcs-mapper/pom.xml @@ -69,11 +69,6 @@ helidon-config-metadata true - - io.helidon.config - helidon-config-metadata-processor - true - org.junit.jupiter junit-jupiter-api @@ -98,18 +93,40 @@ maven-compiler-plugin + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + io.helidon.common.features helidon-common-features-processor ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} + + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.common.features + helidon-common-features-processor + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen + ${helidon.version} + + diff --git a/security/providers/jwt/pom.xml b/security/providers/jwt/pom.xml index 275440b1e47..e711f38b58e 100644 --- a/security/providers/jwt/pom.xml +++ b/security/providers/jwt/pom.xml @@ -61,11 +61,6 @@ helidon-config-metadata true - - io.helidon.config - helidon-config-metadata-processor - true - io.helidon.bundles helidon-bundles-config @@ -95,18 +90,40 @@ maven-compiler-plugin + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + io.helidon.common.features helidon-common-features-processor ${helidon.version} - io.helidon.config - helidon-config-metadata-processor - ${helidon.version}s + io.helidon.config.metadata + helidon-config-metadata-codegen + ${helidon.version} + + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.common.features + helidon-common-features-processor + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen + ${helidon.version} + + diff --git a/security/providers/oidc-common/pom.xml b/security/providers/oidc-common/pom.xml index a2be414384a..9bea3aa1634 100644 --- a/security/providers/oidc-common/pom.xml +++ b/security/providers/oidc-common/pom.xml @@ -128,16 +128,26 @@ - io.helidon.config - helidon-config-metadata-processor + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} diff --git a/security/providers/oidc/pom.xml b/security/providers/oidc/pom.xml index fe634819c7e..2b3095a28c1 100644 --- a/security/providers/oidc/pom.xml +++ b/security/providers/oidc/pom.xml @@ -87,11 +87,6 @@ helidon-config-metadata true - - io.helidon.config - helidon-config-metadata-processor - true - io.helidon.bundles helidon-bundles-config @@ -131,22 +126,32 @@ maven-compiler-plugin + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + io.helidon.common.features helidon-common-features-processor ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} diff --git a/security/security/pom.xml b/security/security/pom.xml index 06d50e84a56..1a2aeeb02e8 100644 --- a/security/security/pom.xml +++ b/security/security/pom.xml @@ -101,18 +101,40 @@ maven-compiler-plugin + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + io.helidon.common.features helidon-common-features-processor ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} + + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.common.features + helidon-common-features-processor + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen + ${helidon.version} + + diff --git a/security/util/pom.xml b/security/util/pom.xml index ae0658e6fc9..ab205d55c09 100644 --- a/security/util/pom.xml +++ b/security/util/pom.xml @@ -77,16 +77,26 @@ - io.helidon.config - helidon-config-metadata-processor + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} diff --git a/tracing/providers/jaeger/pom.xml b/tracing/providers/jaeger/pom.xml index 903fecac641..731cb3709a3 100644 --- a/tracing/providers/jaeger/pom.xml +++ b/tracing/providers/jaeger/pom.xml @@ -99,11 +99,6 @@ helidon-config-metadata true - - io.helidon.config - helidon-config-metadata-processor - true - - - - - - - + + + + + + + + + + + + + + + + + org.apache.maven.plugins + maven-install-plugin + false + + + parent + validate + + install-file + + + ${stage.dir}/core-tck-parent-${version.lib.microprofile-core-profile}.pom + ${stage.dir}/core-tck-parent-${version.lib.microprofile-core-profile}.pom + + + + validate + + install-file + + + ${stage.dir}/${tck.artifact}.jar + ${stage.dir}/${tck.artifact}.pom + ${stage.dir}/${tck.artifact}-sources.jar + + + + diff --git a/microprofile/tests/tck/tck-core-profile/tck-core-profile-test/pom.xml b/microprofile/tests/tck/tck-core-profile/tck-core-profile-test/pom.xml index 15ebe4081bd..7d03f0ded06 100644 --- a/microprofile/tests/tck/tck-core-profile/tck-core-profile-test/pom.xml +++ b/microprofile/tests/tck/tck-core-profile/tck-core-profile-test/pom.xml @@ -61,12 +61,6 @@ - - maven-antrun-plugin - - true - - org.apache.maven.plugins maven-surefire-plugin diff --git a/microprofile/tests/tck/tck-inject/README.md b/microprofile/tests/tck/tck-inject/README.md deleted file mode 100644 index e60b55bddd0..00000000000 --- a/microprofile/tests/tck/tck-inject/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# artifact-install.sh - -This file is used from an ant script in this module to install TCK artifacts in the local Maven repository \ No newline at end of file diff --git a/microprofile/tests/tck/tck-inject/artifact-install.sh b/microprofile/tests/tck/tck-inject/artifact-install.sh deleted file mode 100755 index 402d95eb718..00000000000 --- a/microprofile/tests/tck/tck-inject/artifact-install.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash -# -# Copyright (c) 2023 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. -# - -##script to install the artifact directory contents into a local maven repository - -VERSION="$1" - -# jar -mvn org.apache.maven.plugins:maven-install-plugin:3.0.0-M1:install-file \ --Dfile=target/jakarta.inject-tck-"$VERSION"/jakarta.inject-tck-"$VERSION".jar -DgroupId=jakarta.inject \ --DartifactId=jakarta.inject-tck -Dversion="$VERSION" -Dpackaging=jar diff --git a/microprofile/tests/tck/tck-inject/pom.xml b/microprofile/tests/tck/tck-inject/pom.xml index ed69b990668..6181bcdad07 100644 --- a/microprofile/tests/tck/tck-inject/pom.xml +++ b/microprofile/tests/tck/tck-inject/pom.xml @@ -31,6 +31,14 @@ helidon-microprofile-tests-tck-inject Helidon Microprofile Tests TCK Inject + + 2.0.2 + jakarta.inject-tck-${version.lib.jakarta-inject-tck} + https://download.eclipse.org/jakartaee/dependency-injection/2.0/${tck.filename}-bin.zip + ${tck.filename} + ${project.build.directory}/tck + + tck-inject-test @@ -38,7 +46,9 @@ + org.apache.maven.plugins maven-antrun-plugin + false validate @@ -48,17 +58,49 @@ - - - - - - + + + + + + + + + + + + + + + + + + + + + + org.apache.maven.plugins + maven-install-plugin + false + + + validate + + install-file + + + ${stage.dir}/${tck.filename}.jar + ${stage.dir}/${tck.filename}.pom + ${stage.dir}/${tck.filename}-sources.jar + + + + diff --git a/microprofile/tests/tck/tck-inject/tck-inject-test/pom.xml b/microprofile/tests/tck/tck-inject/tck-inject-test/pom.xml index 37eaebce31c..95853c9fae6 100644 --- a/microprofile/tests/tck/tck-inject/tck-inject-test/pom.xml +++ b/microprofile/tests/tck/tck-inject/tck-inject-test/pom.xml @@ -49,19 +49,13 @@ jakarta.inject jakarta.inject-tck - ${version.lib.jakarta.inject} + ${version.lib.jakarta-inject-tck} test - - maven-antrun-plugin - - true - - org.apache.maven.plugins maven-surefire-plugin @@ -83,8 +77,7 @@ - src/test/java - ../target/jakarta.inject-tck-2.0.2/example/src/test/java + ${project.basedir}/../target/tck-sources diff --git a/microprofile/tests/tck/tck-jsonb/pom.xml b/microprofile/tests/tck/tck-jsonb/pom.xml index 0fa0c737b59..5b4e2b962c1 100644 --- a/microprofile/tests/tck/tck-jsonb/pom.xml +++ b/microprofile/tests/tck/tck-jsonb/pom.xml @@ -31,6 +31,13 @@ helidon-microprofile-tests-tck-jsonb Helidon Microprofile Tests TCK JSONB + + jakarta-jsonb-tck-${version.lib.jakarta.jsonb-api} + https://download.eclipse.org/ee4j/jakartaee-tck/jakartaee10/promoted/eftl/${tck.filename}.zip + jakarta.json.bind-tck-${version.lib.jakarta.jsonb-api} + ${project.build.directory}/tck + + tck-jsonb-test @@ -38,7 +45,9 @@ + org.apache.maven.plugins maven-antrun-plugin + false validate @@ -48,17 +57,36 @@ - - - - - - + + + + + + + + + org.apache.maven.plugins + maven-install-plugin + false + + + validate + + install-file + + + ${stage.dir}/${tck.artifact}.jar + ${stage.dir}/${tck.artifact}.pom + ${stage.dir}/${tck.artifact}-sources.jar + + + + diff --git a/microprofile/tests/tck/tck-jsonb/tck-jsonb-test/pom.xml b/microprofile/tests/tck/tck-jsonb/tck-jsonb-test/pom.xml index 4d1ace0878b..9ffb163515b 100644 --- a/microprofile/tests/tck/tck-jsonb/tck-jsonb-test/pom.xml +++ b/microprofile/tests/tck/tck-jsonb/tck-jsonb-test/pom.xml @@ -57,12 +57,7 @@ - maven-antrun-plugin - - true - - - + org.apache.maven.plugins maven-dependency-plugin diff --git a/microprofile/tests/tck/tck-jsonp/README.md b/microprofile/tests/tck/tck-jsonp/README.md deleted file mode 100644 index e60b55bddd0..00000000000 --- a/microprofile/tests/tck/tck-jsonp/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# artifact-install.sh - -This file is used from an ant script in this module to install TCK artifacts in the local Maven repository \ No newline at end of file diff --git a/microprofile/tests/tck/tck-jsonp/tck-jsonp-pluggability-test/pom.xml b/microprofile/tests/tck/tck-jsonp/tck-jsonp-pluggability-test/pom.xml index ffb0c463be2..9c26e2b10a3 100644 --- a/microprofile/tests/tck/tck-jsonp/tck-jsonp-pluggability-test/pom.xml +++ b/microprofile/tests/tck/tck-jsonp/tck-jsonp-pluggability-test/pom.xml @@ -57,12 +57,7 @@ - maven-antrun-plugin - - true - - - + org.apache.maven.plugins maven-dependency-plugin diff --git a/microprofile/tests/tck/tck-jsonp/tck-jsonp-test/pom.xml b/microprofile/tests/tck/tck-jsonp/tck-jsonp-test/pom.xml index 2c538131741..d1edc2e9501 100644 --- a/microprofile/tests/tck/tck-jsonp/tck-jsonp-test/pom.xml +++ b/microprofile/tests/tck/tck-jsonp/tck-jsonp-test/pom.xml @@ -57,12 +57,7 @@ - maven-antrun-plugin - - true - - - + org.apache.maven.plugins maven-dependency-plugin diff --git a/microprofile/tests/tck/tck-openapi/pom.xml b/microprofile/tests/tck/tck-openapi/pom.xml index 3004f16fbca..223c565a91c 100644 --- a/microprofile/tests/tck/tck-openapi/pom.xml +++ b/microprofile/tests/tck/tck-openapi/pom.xml @@ -102,11 +102,6 @@ 2.3.2 test - - org.testng - testng - test - diff --git a/microprofile/tests/tck/tck-opentracing/pom.xml b/microprofile/tests/tck/tck-opentracing/pom.xml index 64595753443..467fd2e7abd 100644 --- a/microprofile/tests/tck/tck-opentracing/pom.xml +++ b/microprofile/tests/tck/tck-opentracing/pom.xml @@ -69,11 +69,6 @@ io.opentracing opentracing-mock test - - - io.helidon.microprofile.tracing - helidon-microprofile-tracing - test org.testng diff --git a/microprofile/tests/tck/tck-restful/README.md b/microprofile/tests/tck/tck-restful/README.md deleted file mode 100644 index e60b55bddd0..00000000000 --- a/microprofile/tests/tck/tck-restful/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# artifact-install.sh - -This file is used from an ant script in this module to install TCK artifacts in the local Maven repository \ No newline at end of file diff --git a/microprofile/tests/tck/tck-restful/artifact-install.sh b/microprofile/tests/tck/tck-restful/artifact-install.sh deleted file mode 100755 index 9f1c71d7b75..00000000000 --- a/microprofile/tests/tck/tck-restful/artifact-install.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash -# -# Copyright (c) 2023 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. -# - -##script to install the artifact directory contents into a local maven repository - -VERSION="$1" - -# jar -mvn org.apache.maven.plugins:maven-install-plugin:3.0.0-M1:install-file \ --Dfile=target/jakarta-restful-ws-tck-"$VERSION".jar -DgroupId=jakarta.ws.rs \ --DartifactId=jakarta-restful-ws-tck -Dversion="$VERSION" -Dpackaging=jar diff --git a/microprofile/tests/tck/tck-restful/pom.xml b/microprofile/tests/tck/tck-restful/pom.xml index e1a4be0be9a..09f1b946edc 100644 --- a/microprofile/tests/tck/tck-restful/pom.xml +++ b/microprofile/tests/tck/tck-restful/pom.xml @@ -31,6 +31,13 @@ tck-restful Helidon Microprofile Tests TCK Restful + + jakarta-restful-ws-tck-${version.lib.microprofile-restful-tck} + https://download.eclipse.org/ee4j/jakartaee-tck/jakartaee10/staged/eftl/${tck.filename}.zip + ${tck.filename} + ${project.build.directory}/tck + + tck-restful-test @@ -38,7 +45,9 @@ + org.apache.maven.plugins maven-antrun-plugin + false validate @@ -48,17 +57,35 @@ - - - - - - + + + + + + + + org.apache.maven.plugins + maven-install-plugin + false + + + validate + + install-file + + + ${stage.dir}/${tck.artifact}.jar + ${stage.dir}/${tck.artifact}.pom + ${stage.dir}/${tck.artifact}-sources.jar + + + + diff --git a/microprofile/tests/tck/tck-restful/tck-restful-test/pom.xml b/microprofile/tests/tck/tck-restful/tck-restful-test/pom.xml index 2d2317846e4..21360f2a5ea 100644 --- a/microprofile/tests/tck/tck-restful/tck-restful-test/pom.xml +++ b/microprofile/tests/tck/tck-restful/tck-restful-test/pom.xml @@ -95,12 +95,7 @@ - maven-antrun-plugin - - true - - - + org.apache.maven.plugins maven-dependency-plugin From 6ff95b0da1c2e26f0b920a83e25f9a3515077dc8 Mon Sep 17 00:00:00 2001 From: Romain Grecourt Date: Thu, 1 Aug 2024 13:58:48 -0700 Subject: [PATCH 19/37] Uptake Helidon Build Tools v4.0.9 (#9086) --- applications/parent/pom.xml | 4 ++-- examples/quickstarts/helidon-standalone-quickstart-mp/pom.xml | 4 ++-- examples/quickstarts/helidon-standalone-quickstart-se/pom.xml | 4 ++-- pom.xml | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/applications/parent/pom.xml b/applications/parent/pom.xml index e4fec74bd9a..b0116200ca7 100644 --- a/applications/parent/pom.xml +++ b/applications/parent/pom.xml @@ -42,8 +42,8 @@ 3.6.0 3.1.0 3.1.2 - 4.0.6 - 4.0.6 + 4.0.9 + 4.0.9 3.3.0 0.10.2 1.5.0.Final diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/pom.xml b/examples/quickstarts/helidon-standalone-quickstart-mp/pom.xml index 8ce2725c387..bb9060a27ea 100644 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/pom.xml +++ b/examples/quickstarts/helidon-standalone-quickstart-mp/pom.xml @@ -41,8 +41,8 @@ 2.7.5.1 1.6.0 3.0.0-M5 - 4.0.6 - 4.0.6 + 4.0.9 + 4.0.9 3.1.2 3.0.2 0.10.2 diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/pom.xml b/examples/quickstarts/helidon-standalone-quickstart-se/pom.xml index 3c7508ef397..b6b31c4ce54 100644 --- a/examples/quickstarts/helidon-standalone-quickstart-se/pom.xml +++ b/examples/quickstarts/helidon-standalone-quickstart-se/pom.xml @@ -42,8 +42,8 @@ 3.6.0 1.6.0 3.0.0-M5 - 4.0.6 - 4.0.6 + 4.0.9 + 4.0.9 3.0.2 0.10.2 1.5.0.Final diff --git a/pom.xml b/pom.xml index bd5f88935e0..1ba36205316 100644 --- a/pom.xml +++ b/pom.xml @@ -117,7 +117,7 @@ 3.1.0 3.1.2 2.3 - 4.0.6 + 4.0.9 ${version.lib.hibernate} 0.8.5 3.1.2 From eb1066d532df8c307407bc5580287ea401d1b4ad Mon Sep 17 00:00:00 2001 From: Tomas Langer Date: Thu, 1 Aug 2024 23:56:52 +0200 Subject: [PATCH 20/37] 4.x: Excluding generated service descriptors from javadoc plugin(s). (#9082) * Excluding generated service descriptors from javadoc plugin(s). docs/pom.xml modification will work once the change is merged to build tools and we use newer version. * Renamed as in build tools PR. --- docs/pom.xml | 8 ++++++++ integrations/oci/authentication/instance/pom.xml | 4 ++++ integrations/oci/authentication/oke-workload/pom.xml | 4 ++++ integrations/oci/authentication/resource/pom.xml | 4 ++++ pom.xml | 1 + 5 files changed, 21 insertions(+) diff --git a/docs/pom.xml b/docs/pom.xml index 322a0f11009..feebb6ebea1 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -207,6 +207,11 @@ **/generated-test-sources **/extracted-sources/** + + + *__*.java + *_.java + io.helidon* @@ -216,6 +221,9 @@ io.helidon.inject* *.processor* + io.helidon.integrations.oci.authentication.instance + io.helidon.integrations.oci.authentication.resource + io.helidon.integrations.oci.authentication.okeworkload io.helidon* diff --git a/integrations/oci/authentication/instance/pom.xml b/integrations/oci/authentication/instance/pom.xml index 55e5979cc24..9d081392d23 100644 --- a/integrations/oci/authentication/instance/pom.xml +++ b/integrations/oci/authentication/instance/pom.xml @@ -30,6 +30,10 @@ Authentication based on Instance's principal + + true + + io.helidon.integrations.oci diff --git a/integrations/oci/authentication/oke-workload/pom.xml b/integrations/oci/authentication/oke-workload/pom.xml index 5fc00f970b6..36e5764f7da 100644 --- a/integrations/oci/authentication/oke-workload/pom.xml +++ b/integrations/oci/authentication/oke-workload/pom.xml @@ -30,6 +30,10 @@ Authentication based on Workload identity + + true + + io.helidon.integrations.oci diff --git a/integrations/oci/authentication/resource/pom.xml b/integrations/oci/authentication/resource/pom.xml index 3a20556adc3..b8f09dad85f 100644 --- a/integrations/oci/authentication/resource/pom.xml +++ b/integrations/oci/authentication/resource/pom.xml @@ -30,6 +30,10 @@ Authentication based on Resource principal + + true + + io.helidon.integrations.oci diff --git a/pom.xml b/pom.xml index 1ba36205316..9cf02ac252c 100644 --- a/pom.xml +++ b/pom.xml @@ -437,6 +437,7 @@ **/target/**/*.java **/*_.java + **/*__*.java From fcc0fd198a7bcd34e67a32d98f86b36f6b2952d7 Mon Sep 17 00:00:00 2001 From: Romain Grecourt Date: Thu, 1 Aug 2024 14:57:20 -0700 Subject: [PATCH 21/37] Fix release.sh (#9087) --- etc/scripts/release.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/etc/scripts/release.sh b/etc/scripts/release.sh index f719394be30..1f2884eab87 100755 --- a/etc/scripts/release.sh +++ b/etc/scripts/release.sh @@ -113,7 +113,7 @@ exec 6>&1 1>&2 current_version() { # shellcheck disable=SC2086 mvn ${MAVEN_ARGS} -q \ - -f "${WS_DIR}"/file.xml \ + -f "${WS_DIR}"/pom.xml \ -Dexec.executable="echo" \ -Dexec.args="\${project.version}" \ --non-recursive \ @@ -151,7 +151,7 @@ update_version(){ # shellcheck disable=SC2086 mvn ${MAVEN_ARGS} "${ARGS[@]}" \ - -f ${WS_DIR}/parent/file.xml versions:set versions:set-property \ + -f ${WS_DIR}/parent/pom.xml versions:set versions:set-property \ -DgenerateBackupPoms="false" \ -DnewVersion="${version}" \ -Dproperty="helidon.version" \ @@ -270,7 +270,8 @@ deploy_snapshot() { # property. The deployAtEnd option requires version 3.0.0 of maven-deploy-plugin # or newer to work correctly on multi-module systems set -x - mvn "${MAVEN_ARGS}" -e clean deploy \ + # shellcheck disable=SC2086 + mvn ${MAVEN_ARGS} -e clean deploy \ -Parchetypes \ -DskipTests \ -DaltDeploymentRepository="ossrh::${NEXUS_SNAPSHOT_URL}" \ From ca45a8a09958784ba1d9d5bfa2237b2e4d5984f0 Mon Sep 17 00:00:00 2001 From: Joe DiPol Date: Thu, 1 Aug 2024 15:16:25 -0700 Subject: [PATCH 22/37] Upgrade oci-sdk to 3.45.0 (#9083) --- dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/pom.xml b/dependencies/pom.xml index a7d74f72a8e..a26f8ed7fcd 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -126,7 +126,7 @@ 7.0.0.Final 5.12.0 4.1.108.Final - 3.43.2 + 3.45.0 21 - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.config - helidon-examples-config-basics - Helidon Examples Config Basics - - - The simplest example shows how to use Configuration API. - - - - io.helidon.examples.config.basics.Main - - - - - io.helidon.config - helidon-config - - - io.helidon.config - helidon-config-hocon - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/config/basics/src/main/java/io/helidon/examples/config/basics/Main.java b/examples/config/basics/src/main/java/io/helidon/examples/config/basics/Main.java deleted file mode 100644 index e5cae4a4688..00000000000 --- a/examples/config/basics/src/main/java/io/helidon/examples/config/basics/Main.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.config.basics; - -import java.nio.file.Path; -import java.util.List; - -import io.helidon.config.Config; - -import static io.helidon.config.ConfigSources.classpath; - -/** - * Basics example. - */ -public class Main { - - private Main() { - } - - /** - * Executes the example. - * - * @param args arguments - */ - public static void main(String... args) { - Config config = Config.create(classpath("application.conf")); - - int pageSize = config.get("app.page-size").asInt().get(); - - boolean storageEnabled = config.get("app.storageEnabled").asBoolean().orElse(false); - - List basicRange = config.get("app.basic-range").asList(Integer.class).get(); - - Path loggingOutputPath = config.get("logging.outputs.file.name").as(Path.class).get(); - - System.out.println(pageSize); - System.out.println(storageEnabled); - System.out.println(basicRange); - System.out.println(loggingOutputPath); - } - -} diff --git a/examples/config/basics/src/main/java/io/helidon/examples/config/basics/package-info.java b/examples/config/basics/src/main/java/io/helidon/examples/config/basics/package-info.java deleted file mode 100644 index 266ea311291..00000000000 --- a/examples/config/basics/src/main/java/io/helidon/examples/config/basics/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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. - */ - -/** - * The simplest example shows how to use Configuration API. - */ -package io.helidon.examples.config.basics; diff --git a/examples/config/basics/src/main/resources/application.conf b/examples/config/basics/src/main/resources/application.conf deleted file mode 100644 index 012af9e5c2d..00000000000 --- a/examples/config/basics/src/main/resources/application.conf +++ /dev/null @@ -1,69 +0,0 @@ -# -# Copyright (c) 2017, 2021 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. -# - -app { - greeting = "Hello" - name = "Demo" - page-size = 20 - basic-range = [ -20, 20 ] - storagePassphrase = "${AES=thisIsEncriptedPassphrase}" -} - -logging { - outputs { - console { - pattern = simple.colored - level = INFO - } - file { - pattern = verbose.colored - level = DEBUG - name = target/root.log - } - } - level = INFO - app.level = DEBUG - com.oracle.prime.level = WARN -} - -# (this is snippet of complex configuration of security component) -security { - providers: [ # First provider in the list is the default one - { - name = "BMCS" - class = "com.oracle.prime.security.bmcs.BmcsProvider" - BmcsProvider { - # Configuration of OPC (Bare metal) security provider - # (configuration cleaned to be short ...) - - # targets for outbound configuration - targets: [ - { - name = "s2s" - transports = ["http"] - hosts = ["127.0.0.1"] - s2sType = "S2S" - } - #, other targets ... - ] - } - }, - { - name = "ForEndUsers" - class = "com.oracle.prime.examples.security.primeruntime.bmcs.ExampleSecurityProvider" - } - ] -} diff --git a/examples/config/basics/src/main/resources/logging.properties b/examples/config/basics/src/main/resources/logging.properties deleted file mode 100644 index b8635a5024e..00000000000 --- a/examples/config/basics/src/main/resources/logging.properties +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2017, 2021 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. -# - - -handlers = java.util.logging.ConsoleHandler - -java.util.logging.ConsoleHandler.level = FINEST -java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter -java.util.logging.SimpleFormatter.format = [%1$tc] %4$s: %2$s - %5$s %6$s%n - -.level = INFO -io.helidon.config.level = WARNING -io.helidon.config.examples.level = FINEST diff --git a/examples/config/changes/README.md b/examples/config/changes/README.md deleted file mode 100644 index 2f290e98baa..00000000000 --- a/examples/config/changes/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# Helidon Config Changes Example - -This example shows how an application can deal with changes to -configuration. - -## Change notification - -[`OnChangeExample.java`](src/main/java/io/helidon/examples/config/changes/OnChangeExample.java): -uses `Config.onChange`, passing either a method reference (a lambda expression -would also work) which the config system invokes when the config source changes -) - -## Latest-value supplier - -Recall that once your application obtains a `Config` instance, its config values -do not change. The -[`AsSupplierExample.java`](src/main/java/io/helidon/examples/config/changes/AsSupplierExample.java) -example shows how your application can get a config _supplier_ that always reports -the latest config value for a key, including any changes made after your -application obtained the `Config` object. Although this approach does not notify -your application _when_ changes occur, it _does_ permit your code to always use -the most up-to-date value. Sometimes that is all you need. - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-config-changes.jar -``` diff --git a/examples/config/changes/conf/config.yaml b/examples/config/changes/conf/config.yaml deleted file mode 100644 index 000a60490c3..00000000000 --- a/examples/config/changes/conf/config.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# -# Copyright (c) 2017, 2021 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. -# - -# In config.yaml we are going to override default configuration. -# It is supposed to be deployment dependent configuration. - -app: - greeting: Hello diff --git a/examples/config/changes/conf/dev.yaml b/examples/config/changes/conf/dev.yaml deleted file mode 100644 index 3d54809c0b4..00000000000 --- a/examples/config/changes/conf/dev.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2017, 2021 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. -# - -# In dev.yaml we are going to override all lower layer configuration files. -# It is supposed to be development specific configuration. - -# IT SHOULD NOT BE PLACED IN VCS. EACH DEVELOPER CAN CUSTOMIZE THE FILE AS NEEDED. -# I.e. for example with GIT place following line into .gitignore file: -#*/conf/dev.yaml - -app: - name: Developer diff --git a/examples/config/changes/conf/secrets/password b/examples/config/changes/conf/secrets/password deleted file mode 100644 index 5bbaf875819..00000000000 --- a/examples/config/changes/conf/secrets/password +++ /dev/null @@ -1 +0,0 @@ -changeit \ No newline at end of file diff --git a/examples/config/changes/conf/secrets/username b/examples/config/changes/conf/secrets/username deleted file mode 100644 index 1ce97e36c6b..00000000000 --- a/examples/config/changes/conf/secrets/username +++ /dev/null @@ -1 +0,0 @@ -libor \ No newline at end of file diff --git a/examples/config/changes/pom.xml b/examples/config/changes/pom.xml deleted file mode 100644 index 44447b091a4..00000000000 --- a/examples/config/changes/pom.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.config - helidon-examples-config-changes - Helidon Examples Config Changes - - - The example shows how to use Configuration Changes API. - - - - io.helidon.examples.config.changes.Main - - - - - io.helidon.config - helidon-config - - - io.helidon.config - helidon-config-yaml - - - io.helidon.common - helidon-common-reactive - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/config/changes/src/main/java/io/helidon/examples/config/changes/AsSupplierExample.java b/examples/config/changes/src/main/java/io/helidon/examples/config/changes/AsSupplierExample.java deleted file mode 100644 index 33c6cc13461..00000000000 --- a/examples/config/changes/src/main/java/io/helidon/examples/config/changes/AsSupplierExample.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.config.changes; - -import java.time.Duration; -import java.util.Objects; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Supplier; -import java.util.logging.Logger; - -import io.helidon.config.Config; -import io.helidon.config.FileSystemWatcher; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.file; -import static io.helidon.config.PollingStrategies.regular; - -/** - * Example shows how to use Config accessor methods that return {@link Supplier}. - * {@link Supplier} returns always the last loaded config value. - *

      - * The feature is based on using {@link io.helidon.config.spi.PollingStrategy} with - * selected config source(s) to check for changes. - */ -public class AsSupplierExample { - - private static final Logger LOGGER = Logger.getLogger(AsSupplierExample.class.getName()); - - private final AtomicReference lastPrinted = new AtomicReference<>(); - private final ScheduledExecutorService executor = initExecutor(); - - /** - * Executes the example. - */ - public void run() { - Config config = Config - .create(file("conf/dev.yaml") - .optional() - // change watcher is a standalone component that watches for - // changes and notifies the config system when a change occurs - .changeWatcher(FileSystemWatcher.create()), - file("conf/config.yaml") - .optional() - // polling strategy triggers regular checks on the source to check - // for changes, utilizing a concept of "stamp" of the data that is provided - // and validated by the source - .pollingStrategy(regular(Duration.ofSeconds(2))), - classpath("default.yaml")); - - // greeting.get() always return up-to-date value - final Supplier greeting = config.get("app.greeting").asString().supplier(); - // name.get() always return up-to-date value - final Supplier name = config.get("app.name").asString().supplier(); - - // first greeting - printIfChanged(greeting.get() + " " + name.get() + "."); - - // use same Supplier instances to get up-to-date value - executor.scheduleWithFixedDelay( - () -> printIfChanged(greeting.get() + " " + name.get() + "."), - // check every 1 second for changes - 0, 1, TimeUnit.SECONDS); - } - - /** - * Utility to print same message just once. - */ - private void printIfChanged(String message) { - lastPrinted.accumulateAndGet(message, (origValue, newValue) -> { - //print MESSAGE only if changed since the last print - if (!Objects.equals(origValue, newValue)) { - LOGGER.info("[AsSupplier] " + newValue); - } - return newValue; - }); - } - - private static ScheduledExecutorService initExecutor() { - ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); - Runtime.getRuntime().addShutdownHook(new Thread(executor::shutdown)); - return executor; - } - - /** - * Shutdowns executor. - */ - public void shutdown() { - executor.shutdown(); - } - -} diff --git a/examples/config/changes/src/main/java/io/helidon/examples/config/changes/Main.java b/examples/config/changes/src/main/java/io/helidon/examples/config/changes/Main.java deleted file mode 100644 index 9b94bf3179e..00000000000 --- a/examples/config/changes/src/main/java/io/helidon/examples/config/changes/Main.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.config.changes; - -import java.io.IOException; -import java.util.concurrent.TimeUnit; -import java.util.logging.Logger; - -/** - * Config changes examples. - */ -public class Main { - - private static final Logger LOGGER = Logger.getLogger(Main.class.getName()); - - private Main() { - } - - /** - * Executes the example. - * - * @param args arguments - * @throws InterruptedException in case you cannot sleep - * @throws IOException in case of IO error - */ - public static void main(String... args) throws IOException, InterruptedException { - // subscribe using simple onChange function - new OnChangeExample().run(); - // use same Supplier instances to get up-to-date value - AsSupplierExample asSupplier = new AsSupplierExample(); - asSupplier.run(); - - // waiting for user made changes in config files - long sleep = 60; - LOGGER.info("Application is waiting " + sleep + " seconds for change..."); - TimeUnit.SECONDS.sleep(sleep); - - asSupplier.shutdown(); - LOGGER.info("Goodbye."); - } - -} diff --git a/examples/config/changes/src/main/java/io/helidon/examples/config/changes/OnChangeExample.java b/examples/config/changes/src/main/java/io/helidon/examples/config/changes/OnChangeExample.java deleted file mode 100644 index c771c4a9aef..00000000000 --- a/examples/config/changes/src/main/java/io/helidon/examples/config/changes/OnChangeExample.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2017, 2024 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.config.changes; - -import java.util.logging.Logger; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.config.PollingStrategies; - -import static java.time.Duration.ofSeconds; - -/** - * Example shows how to listen on Config node changes using simplified API, {@link Config#onChange(java.util.function.Consumer)}. - * The Function is invoked with new instance of Config. - *

      - * The feature is based on using {@link io.helidon.config.spi.PollingStrategy} with - * selected config source(s) to check for changes. - */ -public class OnChangeExample { - - private static final Logger LOGGER = Logger.getLogger(OnChangeExample.class.getName()); - - /** - * Executes the example. - */ - public void run() { - Config secrets = Config - .builder(ConfigSources.directory("conf/secrets") - .pollingStrategy(PollingStrategies.regular(ofSeconds(5)))) - .disableEnvironmentVariablesSource() - .disableSystemPropertiesSource() - .build(); - - logSecrets(secrets); - - // subscribe using simple onChange consumer -- could be a lambda as well - secrets.onChange(OnChangeExample::logSecrets); - } - - private static void logSecrets(Config secrets) { - LOGGER.info("Loaded secrets are u: " + secrets.get("username").asString().get() - + ", p: " + secrets.get("changeit").asString().get()); - } - -} diff --git a/examples/config/changes/src/main/java/io/helidon/examples/config/changes/package-info.java b/examples/config/changes/src/main/java/io/helidon/examples/config/changes/package-info.java deleted file mode 100644 index 6422ccbd838..00000000000 --- a/examples/config/changes/src/main/java/io/helidon/examples/config/changes/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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. - */ - -/** - * The example shows how to use Configuration Changes API. - */ -package io.helidon.examples.config.changes; diff --git a/examples/config/changes/src/main/resources/default.yaml b/examples/config/changes/src/main/resources/default.yaml deleted file mode 100644 index c4f334a3bb0..00000000000 --- a/examples/config/changes/src/main/resources/default.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# -# Copyright (c) 2017, 2021 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. -# - -# In default.yaml we are going to configure application default values. -# It is expected it is overridden in: -# - conf/config.yaml in production environment -# - conf/dev.yaml by developer on local machine - -app: - greeting: Hi - name: Example diff --git a/examples/config/changes/src/main/resources/logging.properties b/examples/config/changes/src/main/resources/logging.properties deleted file mode 100644 index 31bc145f8d8..00000000000 --- a/examples/config/changes/src/main/resources/logging.properties +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2017, 2021 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. -# - - -handlers = java.util.logging.ConsoleHandler - -java.util.logging.ConsoleHandler.level = FINEST -java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter -java.util.logging.SimpleFormatter.format = [%1$tc] %5$s %6$s%n - -.level = INFO -io.helidon.config.level = WARNING -io.helidon.config.examples.level = FINEST diff --git a/examples/config/git/README.md b/examples/config/git/README.md deleted file mode 100644 index efa442e8f3b..00000000000 --- a/examples/config/git/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# Helidon Config Git Example - -This example shows how to load configuration from a Git repository -and switch which branch to load from at runtime. - -## Prerequisites - -The example assumes that the GitHub repository -has a branch named `test` that contains `application.conf` which sets the key -`greeting` to value `hello`. (The Helidon team has created and populated this -repository.) - -The code in [`Main.java`](src/main/java/io/helidon/examples/config/git/Main.java) -uses the environment variable `ENVIRONMENT_NAME` to fetch the branch name -in the GitHub repository to use; it uses `master` by default (which does _not_ -contain the expected value). - -The example application constructs a `Config` instance from that file in the -GitHub repository and branch, prints out the value for key `greeting`, and -checks to make sure the value is the expected `hello`. - -## Build and run - -```shell -mvn package -export ENVIRONMENT_NAME=test -java -jar target/helidon-examples-config-git.jar -``` diff --git a/examples/config/git/pom.xml b/examples/config/git/pom.xml deleted file mode 100644 index 198d1c29888..00000000000 --- a/examples/config/git/pom.xml +++ /dev/null @@ -1,82 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.config - helidon-examples-config-git - Helidon Examples Config Git - - - The example shows how to use GitConfigSource. - - - - io.helidon.examples.config.git.Main - - - - - io.helidon.config - helidon-config - - - io.helidon.config - helidon-config-hocon - - - io.helidon.config - helidon-config-git - - - org.slf4j - slf4j-jdk14 - - - - - - - org.codehaus.mojo - exec-maven-plugin - - - test - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/config/git/src/main/java/io/helidon/examples/config/git/Main.java b/examples/config/git/src/main/java/io/helidon/examples/config/git/Main.java deleted file mode 100644 index 79b976ea614..00000000000 --- a/examples/config/git/src/main/java/io/helidon/examples/config/git/Main.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.config.git; - -import java.io.IOException; -import java.net.URI; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.config.git.GitConfigSource; - -/** - * Git source example. - *

      - * This example expects: - *

        - *
      1. a Git repository {@code helidonrobot/test-config} which contains: - *
          - *
        1. the branch {@code test} containing {@code application.conf} which sets - * {@code greeting} to {@code hello}, - *
        2. the branch {@code main} containing the file {@code application.conf} - * which sets the property {@code greeting} to any value other than - * {@code hello}, - *
        3. optionally, any other branch in which {@code application.conf} sets - * {@code greeting} to {@code hello}. - *
        - *
      2. the environment variable {@code ENVIRONMENT_NAME} set to: - *
          - *
        1. {@code test}, or - *
        2. the name of the optional additional branch described above. - *
        - *
      - */ -public class Main { - - private static final String ENVIRONMENT_NAME_PROPERTY = "ENVIRONMENT_NAME"; - - private Main() { - } - - /** - * Executes the example. - * - * @param args arguments - * @throws IOException when some git repo operation failed - */ - public static void main(String... args) throws IOException { - - // we expect a name of the current environment in envvar ENVIRONMENT_NAME - // in this example we just set envvar in maven plugin 'exec', but can be set in k8s pod via ConfigMap - Config env = Config.create(ConfigSources.environmentVariables()); - - String branch = env.get(ENVIRONMENT_NAME_PROPERTY).asString().orElse("master"); - - System.out.println("Loading from branch " + branch); - - Config config = Config.create( - GitConfigSource.builder() - .path("application.conf") - .uri(URI.create("https://github.com/helidonrobot/test-config.git")) - .branch(branch) - .build()); - - System.out.println("Greeting is " + config.get("greeting").asString().get()); - assert config.get("greeting").asString().get().equals("hello"); - } - -} diff --git a/examples/config/git/src/main/java/io/helidon/examples/config/git/package-info.java b/examples/config/git/src/main/java/io/helidon/examples/config/git/package-info.java deleted file mode 100644 index 47c2c44eb1d..00000000000 --- a/examples/config/git/src/main/java/io/helidon/examples/config/git/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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. - */ - -/** - * The example shows how to use GitConfigSource. - */ -package io.helidon.examples.config.git; diff --git a/examples/config/git/src/main/resources/logging.properties b/examples/config/git/src/main/resources/logging.properties deleted file mode 100644 index b8635a5024e..00000000000 --- a/examples/config/git/src/main/resources/logging.properties +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2017, 2021 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. -# - - -handlers = java.util.logging.ConsoleHandler - -java.util.logging.ConsoleHandler.level = FINEST -java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter -java.util.logging.SimpleFormatter.format = [%1$tc] %4$s: %2$s - %5$s %6$s%n - -.level = INFO -io.helidon.config.level = WARNING -io.helidon.config.examples.level = FINEST diff --git a/examples/config/mapping/README.md b/examples/config/mapping/README.md deleted file mode 100644 index 12523332066..00000000000 --- a/examples/config/mapping/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Helidon Config Mapping Example - -This example shows how to implement mappers that convert configuration -to POJOs. - -1. [`BuilderExample.java`](src/main/java/io/helidon/examples/config/mapping/BuilderExample.java) -shows how you can add a `builder()` method to a POJO. That method returns a `Builder` -object which the config system uses to update with various key settings and then, -finally, invoke `build()` so the builder can instantiate the POJO with the -assigned values. -2. [`DeserializationExample.java`](src/main/java/io/helidon/examples/config/mapping/DeserializationExample.java) -uses the config system's support for automatic mapping to POJOs that have bean-style -setter methods. -3. [`FactoryMethodExample.java`](src/main/java/io/helidon/examples/config/mapping/FactoryMethodExample.java) -illustrates how you can add a static factory method `create` to a POJO to tell the config -system how to construct a POJO instance. - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-config-mapping.jar -``` diff --git a/examples/config/mapping/pom.xml b/examples/config/mapping/pom.xml deleted file mode 100644 index 872618ac9d7..00000000000 --- a/examples/config/mapping/pom.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.config - helidon-examples-config-mapping - Helidon Examples Config Mapping - - - The example shows how to use Config Mapping functionality. - - - - io.helidon.examples.config.mapping.Main - - - - - io.helidon.config - helidon-config - - - io.helidon.config - helidon-config-hocon - - - io.helidon.config - helidon-config-object-mapping - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/config/mapping/src/main/java/io/helidon/examples/config/mapping/BuilderExample.java b/examples/config/mapping/src/main/java/io/helidon/examples/config/mapping/BuilderExample.java deleted file mode 100644 index 18af2182fcc..00000000000 --- a/examples/config/mapping/src/main/java/io/helidon/examples/config/mapping/BuilderExample.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.config.mapping; - -import java.util.List; -import java.util.function.Supplier; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.config.objectmapping.Value; - -/** - * This example shows how to automatically deserialize configuration instance into POJO beans - * using Builder pattern. - */ -public class BuilderExample { - - private BuilderExample() { - } - - /** - * Executes the example. - * - * @param args arguments - */ - public static void main(String... args) { - Config config = Config.create(ConfigSources.classpath("application.conf")); - - AppConfig appConfig = config - // get "app" sub-node - .get("app") - // let config automatically deserialize the node to new AppConfig instance - // note that this requires additional dependency - config-beans - .as(AppConfig.class) - .get(); - - System.out.println(appConfig); - - // assert values loaded from application.conf - - assert appConfig.getGreeting().equals("Hello"); - - assert appConfig.getPageSize() == 20; - - assert appConfig.getBasicRange().size() == 2; - assert appConfig.getBasicRange().get(0) == -20; - assert appConfig.getBasicRange().get(1) == 20; - } - - /** - * POJO representing an application configuration. - * Class is initialized from {@link Config} instance. - * During deserialization {@link #builder()} builder method} is invoked - * and {@link Builder} is used to initialize properties from configuration. - */ -public static class AppConfig { - private final String greeting; - private final int pageSize; - private final List basicRange; - - private AppConfig(String greeting, int pageSize, List basicRange) { - this.greeting = greeting; - this.pageSize = pageSize; - this.basicRange = basicRange; - } - - public String getGreeting() { - return greeting; - } - - public int getPageSize() { - return pageSize; - } - - public List getBasicRange() { - return basicRange; - } - - @Override - public String toString() { - return "AppConfig:\n" - + " greeting = " + greeting + "\n" - + " pageSize = " + pageSize + "\n" - + " basicRange= " + basicRange; - } - - /** - * Creates new Builder instance used to be initialized from configuration. - * - * @return new Builder instance - */ - public static Builder builder() { - return new Builder(); - } - - /** - * {@link AppConfig} Builder used to be initialized from configuration. - */ - public static class Builder { - private String greeting; - private int pageSize; - private List basicRange; - - private Builder() { - } - - /** - * Set greeting property. - *

      - * POJO property and config key are same, no need to customize it. - * {@link Value} is used just to specify default value - * in case configuration does not contain appropriate value. - * - * @param greeting greeting value - */ - @Value(withDefault = "Hi") - public void setGreeting(String greeting) { - this.greeting = greeting; - } - - /** - * Set a page size. - *

      - * {@link Value} is used to specify correct config key and default value - * in case configuration does not contain appropriate value. - * Original string value is mapped to target int using appropriate - * {@link io.helidon.config.ConfigMappers ConfigMapper}. - * - * @param pageSize page size - */ - @Value(key = "page-size", withDefault = "10") - public void setPageSize(int pageSize) { - this.pageSize = pageSize; - } - - /** - * Set a basic range. - *

      - * {@link Value} is used to specify correct config key and default value supplier - * in case configuration does not contain appropriate value. - * Supplier already returns default value in target type of a property. - * - * @param basicRange basic range - */ - @Value(key = "basic-range", withDefaultSupplier = DefaultBasicRangeSupplier.class) - public void setBasicRange(List basicRange) { - this.basicRange = basicRange; - } - - /** - * Creates new instance of {@link AppConfig} using values provided by configuration. - * - * @return new instance of {@link AppConfig}. - */ - public AppConfig build() { - return new AppConfig(greeting, pageSize, basicRange); - } - } - - /** - * Supplier of default value for {@link Builder#setBasicRange(List) basic-range} property. - */ - public static class DefaultBasicRangeSupplier implements Supplier> { - @Override - public List get() { - return List.of(-10, 10); - } - } - } -} diff --git a/examples/config/mapping/src/main/java/io/helidon/examples/config/mapping/DeserializationExample.java b/examples/config/mapping/src/main/java/io/helidon/examples/config/mapping/DeserializationExample.java deleted file mode 100644 index 2dcb41f3daf..00000000000 --- a/examples/config/mapping/src/main/java/io/helidon/examples/config/mapping/DeserializationExample.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.config.mapping; - -import java.util.List; -import java.util.function.Supplier; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.config.objectmapping.Value; - -/** - * This example shows how to automatically deserialize configuration instance into POJO beans - * using setters. - */ -public class DeserializationExample { - - private DeserializationExample() { - } - - /** - * Executes the example. - * - * @param args arguments - */ - public static void main(String... args) { - Config config = Config.create(ConfigSources.classpath("application.conf")); - - AppConfig appConfig = config - // get "app" sub-node - .get("app") - // let config automatically deserialize the node to new AppConfig instance - .as(AppConfig.class) - .get(); - - System.out.println(appConfig); - - // assert values loaded from application.conf - - assert appConfig.getGreeting().equals("Hello"); - - assert appConfig.getPageSize() == 20; - - assert appConfig.getBasicRange().size() == 2; - assert appConfig.getBasicRange().get(0) == -20; - assert appConfig.getBasicRange().get(1) == 20; - } - - /** - * POJO representing an application configuration. - * Class is initialized from {@link Config} instance. - * During deserialization setter methods are invoked. - */ - public static class AppConfig { - private String greeting; - private int pageSize; - private List basicRange; - - public String getGreeting() { - return greeting; - } - - /** - * Set greeting property. - *

      - * POJO property and config key are same, no need to customize it. - * {@link Value} is used just to specify default value - * in case configuration does not contain appropriate value. - * - * @param greeting greeting value - */ - @Value(withDefault = "Hi") - public void setGreeting(String greeting) { - this.greeting = greeting; - } - - public int getPageSize() { - return pageSize; - } - - /** - * Set a page size. - *

      - * {@link Value} is used to specify correct config key and default value - * in case configuration does not contain appropriate value. - * Original string value is mapped to target int using appropriate - * {@link io.helidon.config.ConfigMappers ConfigMapper}. - * - * @param pageSize page size - */ - @Value(key = "page-size", withDefault = "10") - public void setPageSize(int pageSize) { - this.pageSize = pageSize; - } - - public List getBasicRange() { - return basicRange; - } - - /** - * Set a basic range. - *

      - * {@link Value} is used to specify correct config key and default value supplier - * in case configuration does not contain appropriate value. - * Supplier already returns default value in target type of a property. - * - * @param basicRange basic range - */ - @Value(key = "basic-range", withDefaultSupplier = DefaultBasicRangeSupplier.class) - public void setBasicRange(List basicRange) { - this.basicRange = basicRange; - } - - @Override - public String toString() { - return "AppConfig:\n" - + " greeting = " + greeting + "\n" - + " pageSize = " + pageSize + "\n" - + " basicRange= " + basicRange; - } - - /** - * Supplier of default value for {@link #setBasicRange(List) basic-range} property. - */ - public static class DefaultBasicRangeSupplier implements Supplier> { - @Override - public List get() { - return List.of(-10, 10); - } - } - } -} diff --git a/examples/config/mapping/src/main/java/io/helidon/examples/config/mapping/FactoryMethodExample.java b/examples/config/mapping/src/main/java/io/helidon/examples/config/mapping/FactoryMethodExample.java deleted file mode 100644 index bd5c3849741..00000000000 --- a/examples/config/mapping/src/main/java/io/helidon/examples/config/mapping/FactoryMethodExample.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.config.mapping; - -import java.util.List; -import java.util.function.Supplier; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.config.objectmapping.Value; - -/** - * This example shows how to automatically deserialize configuration instance into POJO beans - * using factory method. - */ -public class FactoryMethodExample { - - private FactoryMethodExample() { - } - - /** - * Executes the example. - * - * @param args arguments - */ - public static void main(String... args) { - Config config = Config.create(ConfigSources.classpath("application.conf")); - - AppConfig appConfig = config - // get "app" sub-node - .get("app") - // let config automatically deserialize the node to new AppConfig instance - .as(AppConfig.class) - .get(); - - System.out.println(appConfig); - - // assert values loaded from application.conf - - assert appConfig.getGreeting().equals("Hello"); - - assert appConfig.getPageSize() == 20; - - assert appConfig.getBasicRange().size() == 2; - assert appConfig.getBasicRange().get(0) == -20; - assert appConfig.getBasicRange().get(1) == 20; - } - - /** - * POJO representing an application configuration. - * Class is initialized from {@link Config} instance. - * During deserialization {@link #create(String, int, List) factory method} is invoked. - */ - public static class AppConfig { - private final String greeting; - private final int pageSize; - private final List basicRange; - - private AppConfig(String greeting, int pageSize, List basicRange) { - this.greeting = greeting; - this.pageSize = pageSize; - this.basicRange = basicRange; - } - - public String getGreeting() { - return greeting; - } - - public int getPageSize() { - return pageSize; - } - - public List getBasicRange() { - return basicRange; - } - - @Override - public String toString() { - return "AppConfig:\n" - + " greeting = " + greeting + "\n" - + " pageSize = " + pageSize + "\n" - + " basicRange= " + basicRange; - } - - /** - * Creates new {@link AppConfig} instances. - *

      - * {@link Value} is used to specify config keys - * and default values in case configuration does not contain appropriate value. - * - * @param greeting greeting - * @param pageSize page size - * @param basicRange basic range - * @return new instance of {@link AppConfig}. - */ - public static AppConfig create(@Value(key = "greeting", withDefault = "Hi") - String greeting, - @Value(key = "page-size", withDefault = "10") - int pageSize, - @Value(key = "basic-range", withDefaultSupplier = DefaultBasicRangeSupplier.class) - List basicRange) { - return new AppConfig(greeting, pageSize, basicRange); - } - - /** - * Supplier of default value for {@code basic-range} property, see {@link #create(String, int, List)}. - */ - public static class DefaultBasicRangeSupplier implements Supplier> { - @Override - public List get() { - return List.of(-10, 10); - } - } - } -} diff --git a/examples/config/mapping/src/main/java/io/helidon/examples/config/mapping/Main.java b/examples/config/mapping/src/main/java/io/helidon/examples/config/mapping/Main.java deleted file mode 100644 index 62dbd3fda4b..00000000000 --- a/examples/config/mapping/src/main/java/io/helidon/examples/config/mapping/Main.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.config.mapping; - -/** - * Runs every example main class in this module/package. - */ -public class Main { - - private Main() { - } - - /** - * Executes the example. - * - * @param args arguments - */ - public static void main(String[] args) { - DeserializationExample.main(args); - FactoryMethodExample.main(args); - BuilderExample.main(args); - } - -} diff --git a/examples/config/mapping/src/main/java/io/helidon/examples/config/mapping/package-info.java b/examples/config/mapping/src/main/java/io/helidon/examples/config/mapping/package-info.java deleted file mode 100644 index 9d61db35a2e..00000000000 --- a/examples/config/mapping/src/main/java/io/helidon/examples/config/mapping/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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. - */ - -/** - * The example shows how to use Config Mapping functionality. - */ -package io.helidon.examples.config.mapping; diff --git a/examples/config/mapping/src/main/resources/application.conf b/examples/config/mapping/src/main/resources/application.conf deleted file mode 100644 index 94835f28b82..00000000000 --- a/examples/config/mapping/src/main/resources/application.conf +++ /dev/null @@ -1,21 +0,0 @@ -# -# Copyright (c) 2017, 2021 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. -# - -app { - greeting = "Hello" - page-size = 20 - basic-range = [ -20, 20 ] -} diff --git a/examples/config/mapping/src/main/resources/logging.properties b/examples/config/mapping/src/main/resources/logging.properties deleted file mode 100644 index b8635a5024e..00000000000 --- a/examples/config/mapping/src/main/resources/logging.properties +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2017, 2021 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. -# - - -handlers = java.util.logging.ConsoleHandler - -java.util.logging.ConsoleHandler.level = FINEST -java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter -java.util.logging.SimpleFormatter.format = [%1$tc] %4$s: %2$s - %5$s %6$s%n - -.level = INFO -io.helidon.config.level = WARNING -io.helidon.config.examples.level = FINEST diff --git a/examples/config/metadata/README.md b/examples/config/metadata/README.md deleted file mode 100644 index 7057c721321..00000000000 --- a/examples/config/metadata/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# Configuration metadata usage example - -This example reads configuration metadata from the classpath and creates a full -`application.yaml` content with all possible configuration. - -## Setup - -This application does not have any root configuration on classpath, so it would generate an empty file. -Add at least one module to `pom.xml` that can be configured to see the output. - -Example: -```xml - - io.helidon.security.providers - helidon-security-providers-oidc - -``` - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-config-metadata.jar > application.yaml -``` diff --git a/examples/config/metadata/pom.xml b/examples/config/metadata/pom.xml deleted file mode 100644 index 832de3f97ad..00000000000 --- a/examples/config/metadata/pom.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.config - helidon-examples-config-metadata - Helidon Examples Config Metadata - - - This example shows possibilities with configuration metadata. To test this, add a configurable library on the classpath - and run the example. - - - - io.helidon.examples.config.metadata.ConfigMetadataMain - - - - - org.eclipse.parsson - parsson - - - io.helidon.config - helidon-config-metadata - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/config/metadata/src/main/java/io/helidon/examples/config/metadata/ConfigMetadataMain.java b/examples/config/metadata/src/main/java/io/helidon/examples/config/metadata/ConfigMetadataMain.java deleted file mode 100644 index a8db687f12d..00000000000 --- a/examples/config/metadata/src/main/java/io/helidon/examples/config/metadata/ConfigMetadataMain.java +++ /dev/null @@ -1,461 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.config.metadata; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -import io.helidon.config.metadata.ConfiguredOption; - -import jakarta.json.Json; -import jakarta.json.JsonArray; -import jakarta.json.JsonObject; -import jakarta.json.JsonReader; -import jakarta.json.JsonReaderFactory; -import jakarta.json.JsonValue; - -/** - * Reads configuration metadata and prints a full configuration example. - */ -public final class ConfigMetadataMain { - private static final Map TYPED_VALUES = Map.of("java.lang.Integer", - new TypedValue("1"), - "java.lang.Boolean", - new TypedValue("true"), - "java.lang.Long", - new TypedValue("1000"), - "java.lang.Short", - new TypedValue("0"), - "java.lang.String", - new TypedValue("value", true), - "java.net.URI", - new TypedValue("https://www.example.net", true), - "java.lang.Class", - new TypedValue("net.example.SomeClass", true), - "java.time.ZoneId", - new TypedValue("UTC", true)); - - private ConfigMetadataMain() { - } - - /** - * Start the example. - * @param args ignored - */ - public static void main(String[] args) throws IOException { - JsonReaderFactory readerFactory = Json.createReaderFactory(Map.of()); - - Enumeration files = ConfigMetadataMain.class.getClassLoader().getResources("META-INF/helidon/config-metadata.json"); - List configuredTypes = new LinkedList<>(); - Map typesMap = new HashMap<>(); - - while (files.hasMoreElements()) { - URL url = files.nextElement(); - try (InputStream is = url.openStream()) { - JsonReader reader = readerFactory.createReader(is, StandardCharsets.UTF_8); - processMetadataJson(configuredTypes, typesMap, reader.readArray()); - } - } - for (ConfiguredType configuredType : configuredTypes) { - if (configuredType.standalone()) { - printType(configuredType, typesMap); - } - } - } - - private static void printType(ConfiguredType configuredType, Map typesMap) { - String prefix = configuredType.prefix(); - System.out.println("# " + configuredType.description()); - System.out.println("# " + configuredType.targetClass()); - System.out.println(prefix + ":"); - printType(configuredType, typesMap, 1, false); - } - - private static void printType(ConfiguredType configuredType, - Map typesMap, - int nesting, - boolean listStart) { - String spaces = " ".repeat(nesting * 2); - Set properties = configuredType.properties(); - boolean isListStart = listStart; - - for (ConfiguredType.ConfiguredProperty property : properties) { - if (property.key() != null && property.key().contains(".*.")) { - // this is a nested key, must be resolved by the parent list node - continue; - } - - printProperty(property, properties, typesMap, nesting, isListStart); - isListStart = false; - } - - List inherited = configuredType.inherited(); - for (String inheritedTypeName : inherited) { - ConfiguredType inheritedType = typesMap.get(inheritedTypeName); - if (inheritedType == null) { - System.out.println(spaces + "# Missing inherited type: " + inheritedTypeName); - } else { - printType(inheritedType, typesMap, nesting, false); - } - } - } - - private static void printProperty(ConfiguredType.ConfiguredProperty property, - Set properties, - Map typesMap, - int nesting, - boolean listStart) { - String spaces = " ".repeat(nesting * 2); - - printDocs(property, spaces, listStart); - - if (property.kind() == ConfiguredOption.Kind.LIST) { - printListProperty(property, properties, typesMap, nesting, spaces); - return; - } - - if (property.kind() == ConfiguredOption.Kind.MAP) { - printMapProperty(property, typesMap, nesting, spaces); - return; - } - - TypedValue typed = TYPED_VALUES.get(property.type()); - if (typed == null) { - // this is a nested type, or a missing type - ConfiguredType nestedType = typesMap.get(property.type()); - if (nestedType == null) { - // either we have a list of allowed values, default value, or this is really a missing type - printAllowedValuesOrMissing(property, typesMap, nesting, spaces); - } else { - // proper nested type - if (property.merge()) { - printType(nestedType, typesMap, nesting, false); - } else { - System.out.println(spaces + property.outputKey() + ":"); - printType(nestedType, typesMap, nesting + 1, false); - } - } - } else { - // this is a "leaf" node - if (property.defaultValue() == null) { - System.out.println(spaces + "# Generated value (property does not have a configured default)"); - } - System.out.println(spaces + property.outputKey() + ": " + toTypedValue(property, typed)); - } - } - - private static void printMapProperty(ConfiguredType.ConfiguredProperty property, - Map typesMap, - int nesting, - String spaces) { - System.out.print(spaces); - System.out.println(property.outputKey() + ":"); - TypedValue typedValue = TYPED_VALUES.get(property.type()); - - String mySpaces = " ".repeat((nesting + 1) * 2); - if (typedValue == null) { - System.out.println(mySpaces + "key: \"Unsupported map value type: " + property.type() + "\""); - } else { - System.out.println(mySpaces + "key-1: " + output(typedValue, typedValue.defaultsDefault())); - System.out.println(mySpaces + "key-2: " + output(typedValue, typedValue.defaultsDefault())); - } - } - - private static void printListProperty(ConfiguredType.ConfiguredProperty property, - Set properties, - Map typesMap, - int nesting, - String spaces) { - System.out.print(spaces); - System.out.print(property.outputKey() + ":"); - ConfiguredType listType = typesMap.get(property.type()); - - if (listType == null) { - if (property.provider()) { - listFromProvider(property, typesMap, nesting, spaces); - } else { - listFromTypes(property, properties, typesMap, nesting, spaces); - } - } else { - System.out.println(); - System.out.print(spaces + "- "); - printType(listType, typesMap, nesting + 1, true); - } - } - - private static void listFromProvider(ConfiguredType.ConfiguredProperty property, - Map typesMap, - int nesting, - String spaces) { - // let's find all supported providers - List providers = new LinkedList<>(); - for (ConfiguredType value : typesMap.values()) { - if (value.provides().contains(property.type())) { - providers.add(value); - } - } - - System.out.println(); - if (providers.isEmpty()) { - System.out.print(spaces + "- # There are no modules on classpath providing " + property.type()); - return; - } - for (ConfiguredType provider : providers) { - System.out.print(spaces + "- "); - if (provider.prefix() != null) { - System.out.println("# " + provider.description()); - System.out.println(spaces + " " + provider.prefix() + ":"); - printType(provider, typesMap, nesting + 2, false); - } else { - printType(provider, typesMap, nesting + 1, true); - } - } - } - - private static void fromProvider(ConfiguredType.ConfiguredProperty property, - Map typesMap, - int nesting) { - String spaces = " ".repeat(nesting + 1); - // let's find all supported providers - List providers = new LinkedList<>(); - for (ConfiguredType value : typesMap.values()) { - if (value.provides().contains(property.type())) { - providers.add(value); - } - } - - if (providers.isEmpty()) { - System.out.println(spaces + " # There are no modules on classpath providing " + property.type()); - return; - } - - for (ConfiguredType provider : providers) { - System.out.println(spaces + " # ****** Provider Configuration ******"); - System.out.println(spaces + " # " + provider.description()); - System.out.println(spaces + " # " + provider.targetClass()); - System.out.println(spaces + " # ************************************"); - if (provider.prefix() != null) { - System.out.println(spaces + " " + provider.prefix() + ":"); - printType(provider, typesMap, nesting + 2, false); - } else { - printType(provider, typesMap, nesting + 1, false); - } - } - } - - private static void listFromTypes(ConfiguredType.ConfiguredProperty property, - Set properties, - Map typesMap, - int nesting, - String spaces) { - // this may be a list defined in configuration itself (*) - String prefix = property.outputKey() + ".*."; - Map children = new HashMap<>(); - for (ConfiguredType.ConfiguredProperty configuredProperty : properties) { - if (configuredProperty.outputKey().startsWith(prefix)) { - children.put(configuredProperty.outputKey().substring(prefix.length()), configuredProperty); - } - } - if (children.isEmpty()) { - // this may be an array of primitive types / String - TypedValue typedValue = TYPED_VALUES.get(property.type()); - if (typedValue == null) { - List allowedValues = property.allowedValues(); - if (allowedValues.isEmpty()) { - System.out.println(); - System.out.println(spaces + "# Missing type: " + property.type()); - } else { - System.out.println(); - typedValue = new TypedValue("", true); - for (ConfiguredType.AllowedValue allowedValue : allowedValues) { - // # Description - // # This is the default value - // actual value - System.out.print(spaces + " - "); - String nextLinePrefix = spaces + " "; - boolean firstLine = true; - - if (allowedValue.description() != null && !allowedValue.description().isBlank()) { - firstLine = false; - System.out.println("#" + allowedValue.description()); - } - if (allowedValue.value().equals(property.defaultValue())) { - if (firstLine) { - firstLine = false; - } else { - System.out.print(nextLinePrefix); - } - System.out.println("# This is the default value"); - } - if (!firstLine) { - System.out.print(nextLinePrefix); - } - System.out.println(output(typedValue, allowedValue.value())); - } - } - } else { - printArray(typedValue); - } - } else { - System.out.println(); - System.out.print(spaces + "- "); - boolean listStart = true; - for (var entry : children.entrySet()) { - ConfiguredType.ConfiguredProperty element = entry.getValue(); - // we must modify the key - element.key(entry.getKey()); - printProperty(element, properties, typesMap, nesting + 1, listStart); - listStart = false; - } - } - } - - private static void printDocs(ConfiguredType.ConfiguredProperty property, String spaces, boolean firstLineNoSpaces) { - String description = property.description(); - description = (description == null || description.isBlank()) ? null : description; - - // type - System.out.print((firstLineNoSpaces ? "" : spaces)); - System.out.print("# "); - System.out.println(property.type()); - - // description - if (description != null) { - description = description.replace('\n', ' '); - System.out.print(spaces); - System.out.print("# "); - System.out.println(description); - } - - // required - if (!property.optional()) { - System.out.print(spaces); - System.out.println("# *********** REQUIRED ***********"); - } - } - - private static void printArray(TypedValue typedValue) { - String element = output(typedValue, typedValue.defaultsDefault()); - String toPrint = " [" + element + "," + element + "]"; - System.out.println(toPrint); - } - - private static String output(TypedValue typed, String value) { - if (typed.escaped()) { - return "\"" + value + "\""; - } - return value; - } - - private static void printAllowedValuesOrMissing(ConfiguredType.ConfiguredProperty property, - Map typesMap, - int nesting, String spaces) { - if (property.provider()) { - System.out.println(spaces + property.outputKey() + ":"); - fromProvider(property, typesMap, nesting); - return; - } - - List allowedValues = property.allowedValues(); - if (allowedValues.isEmpty()) { - if (property.defaultValue() == null) { - System.out.println(spaces + property.outputKey() + ": \"Missing nested type: " + property.type() + "\""); - } else { - System.out.println(spaces + property.outputKey() + ": " + toTypedValue(property, - new TypedValue(property.defaultValue(), - true))); - } - } else { - List values = allowedValues.stream() - .map(ConfiguredType.AllowedValue::value) - .collect(Collectors.toList()); - for (ConfiguredType.AllowedValue allowedValue : allowedValues) { - System.out.println(spaces + "# " + allowedValue.value() + ": " + allowedValue.description() - .replace("\n", " ")); - } - if (property.defaultValue() == null) { - System.out.println(spaces + property.outputKey() + ": \"One of: " + values + "\""); - } else { - System.out.println(spaces + property.outputKey() + ": \"" + property.defaultValue() + "\""); - } - } - } - - private static String toTypedValue(ConfiguredType.ConfiguredProperty property, - TypedValue typed) { - String value = property.defaultValue(); - - if (value == null) { - value = typed.defaultsDefault; - } - - return output(typed, value); - } - - private static void processMetadataJson(List configuredTypes, - Map typesMap, - JsonArray jsonArray) { - for (JsonValue jsonValue : jsonArray) { - processTypeArray(configuredTypes, typesMap, jsonValue.asJsonObject().getJsonArray("types")); - } - } - - private static void processTypeArray(List configuredTypes, - Map typesMap, - JsonArray jsonArray) { - if (jsonArray == null) { - return; - } - for (JsonValue jsonValue : jsonArray) { - JsonObject type = jsonValue.asJsonObject(); - ConfiguredType configuredType = ConfiguredType.create(type); - configuredTypes.add(configuredType); - typesMap.put(configuredType.targetClass(), configuredType); - } - } - - private static final class TypedValue { - private final String defaultsDefault; - private final boolean escaped; - - private TypedValue(String defaultsDefault) { - this(defaultsDefault, false); - } - - private TypedValue(String defaultsDefault, boolean escaped) { - this.defaultsDefault = defaultsDefault; - this.escaped = escaped; - } - - String defaultsDefault() { - return defaultsDefault; - } - - boolean escaped() { - return escaped; - } - } -} diff --git a/examples/config/metadata/src/main/java/io/helidon/examples/config/metadata/ConfiguredType.java b/examples/config/metadata/src/main/java/io/helidon/examples/config/metadata/ConfiguredType.java deleted file mode 100644 index 19b92f83998..00000000000 --- a/examples/config/metadata/src/main/java/io/helidon/examples/config/metadata/ConfiguredType.java +++ /dev/null @@ -1,361 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.config.metadata; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -import io.helidon.config.metadata.ConfiguredOption; - -import jakarta.json.JsonArray; -import jakarta.json.JsonObject; -import jakarta.json.JsonString; -import jakarta.json.JsonValue; - -final class ConfiguredType { - private final Set allProperties = new HashSet<>(); - private final List producerMethods = new LinkedList<>(); - /** - * The type that is built by a builder, or created using create method. - */ - private final String targetClass; - private final boolean standalone; - private final String prefix; - private final String description; - private final List provides; - private final List inherited = new LinkedList<>(); - - ConfiguredType(String targetClass, boolean standalone, String prefix, String description, List provides) { - this.targetClass = targetClass; - this.standalone = standalone; - this.prefix = prefix; - this.description = description; - this.provides = provides; - } - - private static String paramsToString(String[] params) { - String result = Arrays.toString(params); - if (result.startsWith("[") && result.endsWith("]")) { - return result.substring(1, result.length() - 1); - } - return result; - } - - String description() { - return description; - } - - static ConfiguredType create(JsonObject type) { - ConfiguredType ct = new ConfiguredType( - type.getString("type"), - type.getBoolean("standalone", false), - type.getString("prefix", null), - type.getString("description", null), - toList(type.getJsonArray("provides")) - ); - - List producers = toList(type.getJsonArray("producers")); - for (String producer : producers) { - ct.addProducer(ProducerMethod.parse(producer)); - } - List inherits = toList(type.getJsonArray("inherits")); - for (String inherit : inherits) { - ct.addInherited(inherit); - } - - JsonArray options = type.getJsonArray("options"); - for (JsonValue option : options) { - ct.addProperty(ConfiguredProperty.create(option.asJsonObject())); - } - - return ct; - } - - private static List toList(JsonArray array) { - if (array == null) { - return List.of(); - } - List result = new ArrayList<>(array.size()); - - for (JsonValue jsonValue : array) { - result.add(((JsonString) jsonValue).getString()); - } - - return result; - } - - ConfiguredType addProducer(ProducerMethod producer) { - producerMethods.add(producer); - return this; - } - - ConfiguredType addProperty(ConfiguredProperty property) { - allProperties.add(property); - return this; - } - - List producers() { - return producerMethods; - } - - Set properties() { - return allProperties; - } - - String targetClass() { - return targetClass; - } - - boolean standalone() { - return standalone; - } - - String prefix() { - return prefix; - } - - List provides() { - return provides; - } - - @Override - public String toString() { - return targetClass; - } - - void addInherited(String classOrIface) { - inherited.add(classOrIface); - } - - List inherited() { - return inherited; - } - - static final class ProducerMethod { - private final boolean isStatic; - private final String owningClass; - private final String methodName; - private final String[] methodParams; - - ProducerMethod(boolean isStatic, String owningClass, String methodName, String[] methodParams) { - this.isStatic = isStatic; - this.owningClass = owningClass; - this.methodName = methodName; - this.methodParams = methodParams; - } - - public static ProducerMethod parse(String producer) { - int methodSeparator = producer.indexOf('#'); - String owningClass = producer.substring(0, methodSeparator); - int paramBraceStart = producer.indexOf('(', methodSeparator); - String methodName = producer.substring(methodSeparator + 1, paramBraceStart); - int paramBraceEnd = producer.indexOf(')', paramBraceStart); - String parameters = producer.substring(paramBraceStart + 1, paramBraceEnd); - String[] methodParams = parameters.split(","); - - return new ProducerMethod(false, - owningClass, - methodName, - methodParams); - } - - @Override - public String toString() { - return owningClass - + "#" - + methodName + "(" - + paramsToString(methodParams) + ")"; - } - } - - static final class ConfiguredProperty { - private final String builderMethod; - private final String key; - private final String description; - private final String defaultValue; - private final String type; - private final boolean experimental; - private final boolean optional; - private final ConfiguredOption.Kind kind; - private final List allowedValues; - private final boolean provider; - private final boolean merge; - - // if this is a nested type - private ConfiguredType configuredType; - private String outputKey; - - ConfiguredProperty(String builderMethod, - String key, - String description, - String defaultValue, - String type, - boolean experimental, - boolean optional, - ConfiguredOption.Kind kind, - boolean provider, - boolean merge, - List allowedValues) { - this.builderMethod = builderMethod; - this.key = key; - this.description = description; - this.defaultValue = defaultValue; - this.type = type; - this.experimental = experimental; - this.optional = optional; - this.kind = kind; - this.allowedValues = allowedValues; - this.outputKey = key; - this.provider = provider; - this.merge = merge; - } - - public static ConfiguredProperty create(JsonObject json) { - return new ConfiguredProperty( - json.getString("method", null), - json.getString("key", null), - json.getString("description"), - json.getString("defaultValue", null), - json.getString("type", "java.lang.String"), - json.getBoolean("experimental", false), - !json.getBoolean("required", false), - toKind(json.getString("kind", null)), - json.getBoolean("provider", false), - json.getBoolean("merge", false), - toAllowedValues(json.getJsonArray("allowedValues")) - ); - } - - private static ConfiguredOption.Kind toKind(String kind) { - if (kind == null) { - return ConfiguredOption.Kind.VALUE; - } - return ConfiguredOption.Kind.valueOf(kind); - } - - List allowedValues() { - return allowedValues; - } - - private static List toAllowedValues(JsonArray allowedValues) { - if (allowedValues == null) { - return List.of(); - } - List result = new ArrayList<>(allowedValues.size()); - - for (JsonValue allowedValue : allowedValues) { - JsonObject json = allowedValue.asJsonObject(); - result.add(new AllowedValue(json.getString("value"), json.getString("description", null))); - } - - return result; - } - - String builderMethod() { - return builderMethod; - } - - String outputKey() { - return outputKey; - } - - String key() { - return key; - } - - void key(String key) { - this.outputKey = key; - } - - String description() { - return description; - } - - String defaultValue() { - return defaultValue; - } - - String type() { - return type; - } - - boolean experimental() { - return experimental; - } - - boolean optional() { - return optional; - } - - ConfiguredOption.Kind kind() { - return kind; - } - - boolean merge() { - return merge; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ConfiguredProperty that = (ConfiguredProperty) o; - return key.equals(that.key); - } - - @Override - public int hashCode() { - return Objects.hash(key); - } - - @Override - public String toString() { - return key; - } - - boolean provider() { - return provider; - } - } - - static final class AllowedValue { - private final String value; - private final String description; - - private AllowedValue(String value, String description) { - this.value = value; - this.description = description; - } - - String value() { - return value; - } - - String description() { - return description; - } - } -} diff --git a/examples/config/metadata/src/main/java/io/helidon/examples/config/metadata/package-info.java b/examples/config/metadata/src/main/java/io/helidon/examples/config/metadata/package-info.java deleted file mode 100644 index 3e85bb724db..00000000000 --- a/examples/config/metadata/src/main/java/io/helidon/examples/config/metadata/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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 of processing configuration metadata. - */ -package io.helidon.examples.config.metadata; diff --git a/examples/config/overrides/README.md b/examples/config/overrides/README.md deleted file mode 100644 index 966a6435d3b..00000000000 --- a/examples/config/overrides/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# Helidon Config Overrides Example - -This example shows how to load configuration from multiple -configuration sources, specifically where one of the sources _overrides_ other -sources. - -The application treats -[`resources/application.yaml`](./src/main/resources/application.yaml) and -[`conf/priority-config.yaml`](./conf/priority-config.yaml) -as the config sources for the its configuration. - -The `application.yaml` file is packaged along with the application code, while -the files in `conf` would be provided during deployment to tailor the behavior -of the application to that specific environment. - -The application also loads -[`conf/overrides.properties`](./conf/overrides.properties) but as an -_override_ config -source. This file contains key _expressions_ (including wildcards) and values which -take precedence over the settings in the original config sources. - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-config-overrides.jar -``` diff --git a/examples/config/overrides/conf/overrides.properties b/examples/config/overrides/conf/overrides.properties deleted file mode 100644 index f1b566b5bdb..00000000000 --- a/examples/config/overrides/conf/overrides.properties +++ /dev/null @@ -1,29 +0,0 @@ -# -# Copyright (c) 2017, 2021 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. -# - -# Overrides provides central place for -# managing app configuration across envs. - -# key format: $env.$pod... - -# override selected pod (abcdef) logging level -prod.abcdef.logging.level = FINEST - -# "production" environment, any pod -prod.*.logging.level = WARNING - -# "test" environment, any pod -test.*.logging.level = FINE diff --git a/examples/config/overrides/conf/priority-config.yaml b/examples/config/overrides/conf/priority-config.yaml deleted file mode 100644 index ed4c0d2d727..00000000000 --- a/examples/config/overrides/conf/priority-config.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# -# Copyright (c) 2017, 2021 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. -# - -# set context - -env: prod -pod: abcdef - -$env: - $pod: - logging: - level: ERROR - - app: - greeting: Ahoy - page-size: 42 diff --git a/examples/config/overrides/pom.xml b/examples/config/overrides/pom.xml deleted file mode 100644 index 3f302b264b9..00000000000 --- a/examples/config/overrides/pom.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.config - helidon-examples-config-overrides - Helidon Examples Config Overrides - - - The example shows how to use Overrides in Configuration API. - - - - io.helidon.examples.config.overrides.Main - - - - - io.helidon.bundles - helidon-bundles-config - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/config/overrides/src/main/java/io/helidon/examples/config/overrides/Main.java b/examples/config/overrides/src/main/java/io/helidon/examples/config/overrides/Main.java deleted file mode 100644 index 34a9c1679c6..00000000000 --- a/examples/config/overrides/src/main/java/io/helidon/examples/config/overrides/Main.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.config.overrides; - -import java.time.Duration; -import java.util.concurrent.TimeUnit; - -import io.helidon.config.Config; -import io.helidon.config.OverrideSources; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.file; -import static io.helidon.config.PollingStrategies.regular; - -/** - * Overrides example. - *

      - * Shows the Overrides feature where values from config sources might be overridden by override source. - *

      - * In this example, {@code application.yaml} is meant to be default application configuration distributed with an app, containing - * a wildcard configuration nodes representing the defaults for every environment and pod as well as a default definition of - * these values. The source {@code conf/priority-config.yaml} is a higher priority configuration source which can be in a real - * app dynamically changed (i.e. {@code Kubernetes ConfigMap} mapped as the file) and contains the current {@code env} and {@code - * pod} values ({@code prod} and {@code abcdef} in this example) and higher priority default configuration. So far the current - * configuration looks like this: - *

      - * prod:
      - *   abcdef:
      - *     logging:
      - *     level: ERROR
      - *     app:
      - *       greeting:  Ahoy
      - *       page-size: 42
      - *       basic-range:
      - *         - -20
      - *         -  20
      - * 
      - * But the override source just overrides values for environment: {@code prod} and pod: {@code abcdef} (it is the first - * overriding rule found) and value for key {@code prod.abcdef.logging.level = FINEST}. For completeness, we would say that the - * other pods in {@code prod} environment has overridden config value {@code prod.*.logging.level} to {@code WARNING} and all - * pods - * {@code test.*.logging.level} to {@code FINE}. - */ -public final class Main { - - private Main() { - } - - /** - * Executes the example. - * - * @param args arguments - * @throws InterruptedException when a sleeper awakes - */ - public static void main(String... args) throws InterruptedException { - Config config = Config - .builder() - // specify config sources - .sources(file("conf/priority-config.yaml").pollingStrategy(regular(Duration.ofSeconds(1))), - classpath("application.yaml")) - // specify overrides source - .overrides(OverrideSources.file("conf/overrides.properties") - .pollingStrategy(regular(Duration.ofSeconds(1)))) - .build(); - - // Resolve current runtime context - String env = config.get("env").asString().get(); - String pod = config.get("pod").asString().get(); - - // get logging config for the current runtime - Config loggingConfig = config - .get(env) - .get(pod) - .get("logging"); - - // initialize logging from config - initLogging(loggingConfig); - - // react on changes of logging configuration - loggingConfig.onChange(Main::initLogging); - - TimeUnit.MINUTES.sleep(1); - } - - /** - * Initialize logging from config. - */ - private static void initLogging(Config loggingConfig) { - String level = loggingConfig.get("level").asString().orElse("WARNING"); - //e.g. initialize logging using configured level... - - System.out.println("Set logging level to " + level + "."); - } - -} diff --git a/examples/config/overrides/src/main/java/io/helidon/examples/config/overrides/package-info.java b/examples/config/overrides/src/main/java/io/helidon/examples/config/overrides/package-info.java deleted file mode 100644 index 52f2846cd81..00000000000 --- a/examples/config/overrides/src/main/java/io/helidon/examples/config/overrides/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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. - */ - -/** - * The example shows how to use Overrides in Configuration API. - */ -package io.helidon.examples.config.overrides; diff --git a/examples/config/overrides/src/main/resources/application.yaml b/examples/config/overrides/src/main/resources/application.yaml deleted file mode 100644 index b0c0c55f9ca..00000000000 --- a/examples/config/overrides/src/main/resources/application.yaml +++ /dev/null @@ -1,35 +0,0 @@ -# -# Copyright (c) 2017, 2021 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. -# - -# default context - -env: dev -pod: local - -# app config -# key format: $env.$pod... - -$env: - $pod: - logging: - level: CONFIG - - app: - greeting: Hello - page-size: 20 - basic-range: - - -20 - - 20 diff --git a/examples/config/overrides/src/main/resources/logging.properties b/examples/config/overrides/src/main/resources/logging.properties deleted file mode 100644 index b8635a5024e..00000000000 --- a/examples/config/overrides/src/main/resources/logging.properties +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2017, 2021 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. -# - - -handlers = java.util.logging.ConsoleHandler - -java.util.logging.ConsoleHandler.level = FINEST -java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter -java.util.logging.SimpleFormatter.format = [%1$tc] %4$s: %2$s - %5$s %6$s%n - -.level = INFO -io.helidon.config.level = WARNING -io.helidon.config.examples.level = FINEST diff --git a/examples/config/pom.xml b/examples/config/pom.xml deleted file mode 100644 index 27a8ce96425..00000000000 --- a/examples/config/pom.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples - helidon-examples-project - 4.1.0-SNAPSHOT - - io.helidon.examples.config - helidon-examples-config-project - pom - Helidon Examples Config - - - basics - changes - git - mapping - overrides - sources - profiles - metadata - - - diff --git a/examples/config/profiles/README.md b/examples/config/profiles/README.md deleted file mode 100644 index 8c98e3308cc..00000000000 --- a/examples/config/profiles/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# Helidon Config Profiles Example - -This example shows how to load configuration from multiple -configuration sources using profiles. - -This example contains the following profiles: - -1. no profile - if you start the application with no profile, the usual `src/main/resources/application.yaml` will be used -2. `local` - `src/main/resources/application-local.yaml` will be used -3. `dev` - has an explicit profile file `config-profile-dev.yaml` on classpath that defines an inlined configuration -4. `stage` - has an explicit profile file `config-profile-stage.yaml` on classpath that defines a classpath config source -4. `prod` - has an explicit profile file `config-profile-prod.yaml` on file system that defines a path config source - -To switch profiles -- either use a system property `config.profile` -- or use an environment variable `HELIDON_CONFIG_PROFILE` - - -## How to run this example: - -Build the application -```shell -mvn clean package -``` - -Run it with a profile -```shell -java -Dconfig.profile=prod -jar target/helidon-examples-config-profiles.jar -``` - -Changing the profile name should use different configuration. \ No newline at end of file diff --git a/examples/config/profiles/config-profile-prod.yaml b/examples/config/profiles/config-profile-prod.yaml deleted file mode 100644 index f0cf375cc49..00000000000 --- a/examples/config/profiles/config-profile-prod.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) 2021 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. -# - -sources: - - type: "environment-variables" - - type: "system-properties" - - type: "file" - properties: - path: "config/config-prod.yaml" diff --git a/examples/config/profiles/config/config-prod.yaml b/examples/config/profiles/config/config-prod.yaml deleted file mode 100644 index ee020122c09..00000000000 --- a/examples/config/profiles/config/config-prod.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2021 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. -# - -message: "config/config-prod.yaml" diff --git a/examples/config/profiles/pom.xml b/examples/config/profiles/pom.xml deleted file mode 100644 index e3c60c19fbe..00000000000 --- a/examples/config/profiles/pom.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.config - helidon-examples-config-profiles - Helidon Examples Config Profiles - - - The example shows how to use Config Profiles (meta configuration). - - - - io.helidon.examples.config.profiles.Main - - - - - io.helidon.config - helidon-config - - - io.helidon.config - helidon-config-yaml - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/config/profiles/src/main/java/io/helidon/examples/config/profiles/Main.java b/examples/config/profiles/src/main/java/io/helidon/examples/config/profiles/Main.java deleted file mode 100644 index 0077a16939d..00000000000 --- a/examples/config/profiles/src/main/java/io/helidon/examples/config/profiles/Main.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2021 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.config.profiles; - -import io.helidon.config.Config; - -/** - * Example main class. - */ -public final class Main { - private Main() { - } - - /** - * Main method. - * - * @param args ignored - */ - public static void main(String[] args) { - Config config = Config.create(); - - System.out.println("Configured message: " + config.get("message").asString().orElse("MISSING")); - } -} diff --git a/examples/config/profiles/src/main/java/io/helidon/examples/config/profiles/package-info.java b/examples/config/profiles/src/main/java/io/helidon/examples/config/profiles/package-info.java deleted file mode 100644 index bb7cb9ee79e..00000000000 --- a/examples/config/profiles/src/main/java/io/helidon/examples/config/profiles/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 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 showing usage of configuration profiles in Helidon SE. - */ -package io.helidon.examples.config.profiles; diff --git a/examples/config/profiles/src/main/resources/application-local.yaml b/examples/config/profiles/src/main/resources/application-local.yaml deleted file mode 100644 index f54597e9d16..00000000000 --- a/examples/config/profiles/src/main/resources/application-local.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2021 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. -# - -message: "src/main/resources/application-local.yaml" diff --git a/examples/config/profiles/src/main/resources/application-stage.yaml b/examples/config/profiles/src/main/resources/application-stage.yaml deleted file mode 100644 index 7343ff57108..00000000000 --- a/examples/config/profiles/src/main/resources/application-stage.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2021 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. -# - -message: "src/main/resources/application-stage.yaml" diff --git a/examples/config/profiles/src/main/resources/application.yaml b/examples/config/profiles/src/main/resources/application.yaml deleted file mode 100644 index 3eee73c1582..00000000000 --- a/examples/config/profiles/src/main/resources/application.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2021 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. -# - -message: "src/main/resources/application.yaml" diff --git a/examples/config/profiles/src/main/resources/config-profile-dev.yaml b/examples/config/profiles/src/main/resources/config-profile-dev.yaml deleted file mode 100644 index 345d2f00304..00000000000 --- a/examples/config/profiles/src/main/resources/config-profile-dev.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2021 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. -# - -sources: - - type: "inlined" - properties: - message: "inlined in dev profile" diff --git a/examples/config/profiles/src/main/resources/config-profile-stage.yaml b/examples/config/profiles/src/main/resources/config-profile-stage.yaml deleted file mode 100644 index 9740180c872..00000000000 --- a/examples/config/profiles/src/main/resources/config-profile-stage.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2021 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. -# - -sources: - - type: "classpath" - properties: - resource: "application-stage.yaml" diff --git a/examples/config/sources/README.md b/examples/config/sources/README.md deleted file mode 100644 index cfb5c321080..00000000000 --- a/examples/config/sources/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Helidon Config Sources Example - -This example shows how to load configuration from multiple -configuration sources. - -1. [`DirectorySourceExample.java`](src/main/java/io/helidon/examples/config/sources/DirectorySourceExample.java) -reads configuration from multiple files in a directory by specifying only the directory. -2. [`LoadSourcesExample.java`](src/main/java/io/helidon/examples/config/sources/LoadSourcesExample.java) -uses _meta-configuration_ files [`conf/meta-config.yaml`](./conf/meta-config.yaml) -and [`src/main/resources/meta-config.yaml`](./src/main/resources/meta-config.yaml) -which contain not the configuration itself but -_instructions for loading_ the configuration: what type, from where, etc. It also -applies a filter to modify config values whose keys match a certain pattern. -3. [`WithSourcesExample.java`](src/main/java/io/helidon/examples/config/sources/WithSourcesExample.java) -combines multiple config sources into a single configuration instance (and adds a -filter. - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-config-sources.jar -``` diff --git a/examples/config/sources/conf/config.yaml b/examples/config/sources/conf/config.yaml deleted file mode 100644 index c0794062841..00000000000 --- a/examples/config/sources/conf/config.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2017, 2021 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. -# - -# In config.yaml we are going to override default configuration. -# It is supposed to be deployment dependent configuration. - -meta: - env: PROD - -app: - page-size: 10 - diff --git a/examples/config/sources/conf/dev.yaml b/examples/config/sources/conf/dev.yaml deleted file mode 100644 index 10ca8dc5fdd..00000000000 --- a/examples/config/sources/conf/dev.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright (c) 2017, 2021 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. -# - -# In dev.yaml we are going to override all lower layer configuration files. -# It is supposed to be development specific configuration. - -# IT SHOULD NOT BE PLACED IN VCS. EACH DEVELOPER CAN CUSTOMIZE THE FILE AS NEEDED. -# I.e. for example with GIT place following line into .gitignore file: -#*/conf/dev.yaml - -meta: - env: DEV - -component: - audit: - logging: - level: fine diff --git a/examples/config/sources/conf/meta-config.yaml b/examples/config/sources/conf/meta-config.yaml deleted file mode 100644 index 3153da4a79c..00000000000 --- a/examples/config/sources/conf/meta-config.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright (c) 2017, 2021 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. -# - -sources: - - type: "environment-variables" - - type: "system-properties" - - type: "file" - properties: - path: "conf/dev.yaml" - optional: true - - type: "file" - properties: - path: "conf/config.yaml" - optional: true - - type: "classpath" - properties: - resource: "default.yaml" diff --git a/examples/config/sources/conf/secrets/password b/examples/config/sources/conf/secrets/password deleted file mode 100644 index 5bbaf875819..00000000000 --- a/examples/config/sources/conf/secrets/password +++ /dev/null @@ -1 +0,0 @@ -changeit \ No newline at end of file diff --git a/examples/config/sources/conf/secrets/username b/examples/config/sources/conf/secrets/username deleted file mode 100644 index 1ce97e36c6b..00000000000 --- a/examples/config/sources/conf/secrets/username +++ /dev/null @@ -1 +0,0 @@ -libor \ No newline at end of file diff --git a/examples/config/sources/pom.xml b/examples/config/sources/pom.xml deleted file mode 100644 index 5ae02bd2861..00000000000 --- a/examples/config/sources/pom.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.config - helidon-examples-config-sources - Helidon Examples Config Sources - - - This example shows how to merge the configuration from different sources. - - - - io.helidon.examples.config.sources.Main - - - - - io.helidon.config - helidon-config - - - io.helidon.config - helidon-config-yaml - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/config/sources/src/main/java/io/helidon/examples/config/sources/DirectorySourceExample.java b/examples/config/sources/src/main/java/io/helidon/examples/config/sources/DirectorySourceExample.java deleted file mode 100644 index d058cf65e2b..00000000000 --- a/examples/config/sources/src/main/java/io/helidon/examples/config/sources/DirectorySourceExample.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2017, 2024 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.config.sources; - -import io.helidon.config.Config; - -import static io.helidon.config.ConfigSources.directory; - -/** - * This example shows how to read configuration from several files placed in selected directory. - */ -public class DirectorySourceExample { - - private DirectorySourceExample() { - } - - /** - * Executes the example. - * - * @param args arguments - */ - public static void main(String... args) { - /* - Creates a config from files from specified directory. - E.g. Kubernetes Secrets: - */ - - Config secrets = Config.builder(directory("conf/secrets")) - .disableEnvironmentVariablesSource() - .disableSystemPropertiesSource() - .build(); - - String username = secrets.get("username").asString().get(); - System.out.println("Username: " + username); - assert username.equals("libor"); - - String password = secrets.get("changeit").asString().get(); - System.out.println("Password: " + password); - assert password.equals("changeit"); - } - -} diff --git a/examples/config/sources/src/main/java/io/helidon/examples/config/sources/LoadSourcesExample.java b/examples/config/sources/src/main/java/io/helidon/examples/config/sources/LoadSourcesExample.java deleted file mode 100644 index fec701180bd..00000000000 --- a/examples/config/sources/src/main/java/io/helidon/examples/config/sources/LoadSourcesExample.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.config.sources; - -import io.helidon.config.Config; -import io.helidon.config.ConfigValue; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.file; - -/** - * This example shows how to merge the configuration from different sources - * loaded from meta configuration. - * - * @see WithSourcesExample - */ -public class LoadSourcesExample { - - private LoadSourcesExample() { - } - - /** - * Executes the example. - * - * @param args arguments - */ - public static void main(String... args) { - /* - Creates a configuration from list of config sources loaded from meta sources: - - conf/meta-config.yaml - - deployment dependent meta-config file, loaded from file on filesystem; - - meta-config.yaml - application default meta-config file, loaded form classpath; - with a filter which convert values with keys ending with "level" to upper case - */ - - Config metaConfig = Config.create(file("conf/meta-config.yaml").optional(), - classpath("meta-config.yaml")); - - Config config = Config.builder() - .config(metaConfig) - .addFilter((key, stringValue) -> key.name().equals("level") ? stringValue.toUpperCase() : stringValue) - .build(); - - // Optional environment type, from dev.yaml: - ConfigValue env = config.get("meta.env").asString(); - env.ifPresent(e -> System.out.println("Environment: " + e)); - assert env.get().equals("DEV"); - - // Default value (default.yaml): Config Sources Example - String appName = config.get("app.name").asString().get(); - System.out.println("Name: " + appName); - assert appName.equals("Config Sources Example"); - - // Page size, from config.yaml: 10 - int pageSize = config.get("app.page-size").asInt().get(); - System.out.println("Page size: " + pageSize); - assert pageSize == 10; - - // Applied filter (uppercase logging level), from dev.yaml: finest -> FINEST - String level = config.get("component.audit.logging.level").asString().get(); - System.out.println("Level: " + level); - assert level.equals("FINE"); - } - -} diff --git a/examples/config/sources/src/main/java/io/helidon/examples/config/sources/Main.java b/examples/config/sources/src/main/java/io/helidon/examples/config/sources/Main.java deleted file mode 100644 index a7a9aa19901..00000000000 --- a/examples/config/sources/src/main/java/io/helidon/examples/config/sources/Main.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.config.sources; - -/** - * Runs every example main class in this module/package. - */ -public class Main { - - private Main() { - } - - /** - * Executes the example. - * - * @param args arguments - */ - public static void main(String[] args) { - WithSourcesExample.main(args); - LoadSourcesExample.main(args); - DirectorySourceExample.main(args); - } - -} diff --git a/examples/config/sources/src/main/java/io/helidon/examples/config/sources/WithSourcesExample.java b/examples/config/sources/src/main/java/io/helidon/examples/config/sources/WithSourcesExample.java deleted file mode 100644 index 1d214572e5e..00000000000 --- a/examples/config/sources/src/main/java/io/helidon/examples/config/sources/WithSourcesExample.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.config.sources; - -import io.helidon.config.Config; -import io.helidon.config.ConfigValue; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.file; - -/** - * This example shows how to merge the configuration from different sources. - * - * @see LoadSourcesExample - */ -public class WithSourcesExample { - - private WithSourcesExample() { - } - - /** - * Executes the example. - * - * @param args arguments - */ - public static void main(String... args) { - /* - Creates a config source composed of following sources: - - conf/dev.yaml - developer specific configuration, should not be placed in VCS; - - conf/config.yaml - deployment dependent configuration, for example prod, stage, etc; - - default.yaml - application default values, loaded form classpath; - with a filter which convert values with keys ending with "level" to upper case - */ - - Config config = Config - .builder(file("conf/dev.yaml").optional(), - file("conf/config.yaml").optional(), - classpath("default.yaml")) - .addFilter((key, stringValue) -> key.name().equals("level") ? stringValue.toUpperCase() : stringValue) - .build(); - - // Environment type, from dev.yaml: - ConfigValue env = config.get("meta.env").asString(); - env.ifPresent(e -> System.out.println("Environment: " + e)); - assert env.get().equals("DEV"); - - // Default value (default.yaml): Config Sources Example - String appName = config.get("app.name").asString().get(); - System.out.println("Name: " + appName); - assert appName.equals("Config Sources Example"); - - // Page size, from config.yaml: 10 - int pageSize = config.get("app.page-size").asInt().get(); - System.out.println("Page size: " + pageSize); - assert pageSize == 10; - - // Applied filter (uppercase logging level), from dev.yaml: finest -> FINEST - String level = config.get("component.audit.logging.level").asString().get(); - System.out.println("Level: " + level); - assert level.equals("FINE"); - } - -} diff --git a/examples/config/sources/src/main/java/io/helidon/examples/config/sources/package-info.java b/examples/config/sources/src/main/java/io/helidon/examples/config/sources/package-info.java deleted file mode 100644 index aa3a06ec8d4..00000000000 --- a/examples/config/sources/src/main/java/io/helidon/examples/config/sources/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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. - */ - -/** - * This example shows how to merge the configuration from different sources. - */ -package io.helidon.examples.config.sources; diff --git a/examples/config/sources/src/main/resources/default.yaml b/examples/config/sources/src/main/resources/default.yaml deleted file mode 100644 index 94a8de205eb..00000000000 --- a/examples/config/sources/src/main/resources/default.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# -# Copyright (c) 2017, 2021 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. -# - -# In default.yaml we are going to configure application default values. -# It is expected it is overridden in: -# - conf/config.yaml in production environment -# - conf/dev.yaml by developer on local machine - -app: - name: Config Sources Example - page-size: 20 - -component: - audit: - logging: - level: info - monitoring: - logging: - level: warning diff --git a/examples/config/sources/src/main/resources/logging.properties b/examples/config/sources/src/main/resources/logging.properties deleted file mode 100644 index b8635a5024e..00000000000 --- a/examples/config/sources/src/main/resources/logging.properties +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2017, 2021 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. -# - - -handlers = java.util.logging.ConsoleHandler - -java.util.logging.ConsoleHandler.level = FINEST -java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter -java.util.logging.SimpleFormatter.format = [%1$tc] %4$s: %2$s - %5$s %6$s%n - -.level = INFO -io.helidon.config.level = WARNING -io.helidon.config.examples.level = FINEST diff --git a/examples/config/sources/src/main/resources/meta-config.yaml b/examples/config/sources/src/main/resources/meta-config.yaml deleted file mode 100644 index 20af0f805f0..00000000000 --- a/examples/config/sources/src/main/resources/meta-config.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# -# Copyright (c) 2017, 2021 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. -# - -# ordered list of sources -sources: - - type: "classpath" - properties: - resource: "default.yaml" diff --git a/examples/config/sources/src/main/resources/overrides.properties b/examples/config/sources/src/main/resources/overrides.properties deleted file mode 100644 index 717a177f19d..00000000000 --- a/examples/config/sources/src/main/resources/overrides.properties +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2017, 2021 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. -# - -component.*.logging.level = finest diff --git a/examples/cors/README.md b/examples/cors/README.md deleted file mode 100644 index 0216c09bc4b..00000000000 --- a/examples/cors/README.md +++ /dev/null @@ -1,188 +0,0 @@ - -# Helidon SE CORS Example - -This example shows a simple greeting application, similar to the one from the -Helidon SE QuickStart, enhanced with CORS support. - -Look at the `resources/application.yaml` file and notice the `restrictive-cors` -section. (We'll come back to the `cors` section later.) The `Main#corsSupportForGreeting` method loads this -configuration and uses it to set up CORS for the application's endpoints. - -Near the end of the `resources/logging.properties` file, a commented line would turn on `FINE -` logging that would reveal how the Helidon CORS support makes it decisions. To see that logging, -uncomment that line and then package and run the application. - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-cors.jar -``` - -## Using the app endpoints as with the "classic" greeting app - -These normal greeting app endpoints work just as in the original greeting app: - -```shell -curl -X GET http://localhost:8080/greet -{"message":"Hello World!"} - -curl -X GET http://localhost:8080/greet/Joe -{"message":"Hello Joe!"} - -curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}' http://localhost:8080/greet/greeting - -curl -X GET http://localhost:8080/greet/Jose -{"message":"Hola Jose!"} -``` - -## Using CORS - -### Sending "simple" CORS requests - -The following requests illustrate the CORS protocol with the example app. - -By setting `Origin` and `Host` headers that do not indicate the same system we trigger CORS processing in the - server: - -```shell -# Follow the CORS protocol for GET -curl -i -X GET -H "Origin: http://foo.com" -H "Host: here.com" http://localhost:8080/greet - -HTTP/1.1 200 OK -Access-Control-Allow-Origin: * -Content-Type: application/json -Date: Thu, 30 Apr 2020 17:25:51 -0500 -Vary: Origin -connection: keep-alive -content-length: 27 - -{"greeting":"Hola World!"} -``` -Note the new headers `Access-Control-Allow-Origin` and `Vary` in the response. - -The same happens for a `GET` requesting a personalized greeting (by passing the name of the - person to be greeted): -```shell -curl -i -X GET -H "Origin: http://foo.com" -H "Host: here.com" http://localhost:8080/greet/Joe - -HTTP/1.1 200 OK -Date: Wed, 31 Jan 2024 11:58:06 +0100 -Access-Control-Allow-Origin: * -Connection: keep-alive -Content-Length: 24 -Content-Type: application/json -Vary: ORIGIN - -{"greeting":"Hola Joe!"} -``` -These two `GET` requests work because the `Main#corsSupportForGreeting` method adds a default `CrossOriginConfig` to the -`CorsSupport.Builder` it sets up. This is in addition to adding a `CrossOriginConfig` based on the `restrictive-cors` -configuration in `application.yaml` we looked at earlier. - -These are what CORS calls "simple" requests; the CORS protocol for these adds headers to the request and response which -the client and server exchange anyway. - -### "Non-simple" CORS requests - -The CORS protocol requires the client to send a _pre-flight_ request before sending a request - that changes state on the server, such as `PUT` or `DELETE`, and to check the returned status - and headers to make sure the server is willing to accept the actual request. CORS refers to such `PUT` and `DELETE` - requests as "non-simple" ones. - -This command sends a pre-flight `OPTIONS` request to see if the server will accept a subsequent `PUT` request from the -specified origin to change the greeting: -```shell -curl -i -X OPTIONS \ - -H "Access-Control-Request-Method: PUT" \ - -H "Origin: http://foo.com" \ - -H "Host: here.com" \ - http://localhost:8080/greet/greeting - -HTTP/1.1 200 OK -Date: Wed, 31 Jan 2024 12:00:15 +0100 -Access-Control-Allow-Methods: PUT -Access-Control-Allow-Origin: http://foo.com -Access-Control-Max-Age: 3600 -Connection: keep-alive -Content-Length: 0 -``` -The successful status and the returned `Access-Control-Allow-xxx` headers indicate that the - server accepted the pre-flight request. That means it is OK for us to send `PUT` request to perform the actual change - of greeting. (See below for how the server rejects a pre-flight request.) -```shell -curl -i -X PUT \ - -H "Origin: http://foo.com" \ - -H "Host: here.com" \ - -H "Access-Control-Allow-Methods: PUT" \ - -H "Access-Control-Allow-Origin: http://foo.com" \ - -H "Content-Type: application/json" \ - -d "{ \"greeting\" : \"Cheers\" }" \ - http://localhost:8080/greet/greeting - -HTTP/1.1 204 No Content -Date: Wed, 31 Jan 2024 12:01:45 +0100 -Access-Control-Allow-Origin: http://foo.com -Connection: keep-alive -Content-Length: 0 -Vary: ORIGIN -``` -And we run one more `GET` to observe the change in the greeting: -```shell -curl -i -X GET -H "Origin: http://foo.com" -H "Host: here.com" http://localhost:8080/greet/Joe - -HTTP/1.1 200 OK -Date: Wed, 31 Jan 2024 12:02:13 +0100 -Access-Control-Allow-Origin: * -Connection: keep-alive -Content-Length: 26 -Content-Type: application/json -Vary: ORIGIN - -{"greeting":"Cheers Joe!"} -``` -Note that the tests in the example `MainTest` class follow these same steps. - -## Using overrides - -The `Main#corsSupportForGreeting` method loads override settings for any other CORS set-up if the config contains a -"cors" section. (That section is initially commented out in the example `application.yaml` file.) Not all applications -need this feature, but the example shows how easy it is to add. - -With the same server running, repeat the `OPTIONS` request from above, but change the `Origin` header to refer to -`other.com`: -```shell -curl -i -X OPTIONS \ - -H "Access-Control-Request-Method: PUT" \ - -H "Origin: http://other.com" \ - -H "Host: here.com" \ - http://localhost:8080/greet/greeting -HTTP/1.1 403 CORS origin is not in allowed list -Date: Wed, 31 Jan 2024 12:02:51 +0100 -Connection: keep-alive -Content-Length: 0 -``` -This fails because the app set up CORS using the "restrictive-cors" configuration in `application.yaml` which allows -sharing only with `foo.com` and `there.com`, not with `other.com`. - -Stop the running app, uncomment the commented section at the end of `application.yaml`, and build and run the app again. -```shell -mvn package -java -jar target/helidon-examples-cors.jar -``` -Send the previous `OPTIONS` request again and note the successful result: -```shell -HTTP/1.1 200 OK -Date: Wed, 31 Jan 2024 12:05:36 +0100 -Access-Control-Allow-Methods: PUT -Access-Control-Allow-Origin: http://other.com -Access-Control-Max-Age: 3600 -Connection: keep-alive -Content-Length: 0 -``` -The application uses the now-uncommented portion of the config file to override the rest of the CORS set-up. You can -choose whatever key name you want for the override. Just make sure you tell your end users whatever the key is your app -uses for overrides. - -A real application might read the normal configuration (`restrictive-cors`) from one config source and any overrides -from another. This example combines them in one config source just for simplicity. diff --git a/examples/cors/pom.xml b/examples/cors/pom.xml deleted file mode 100644 index 6538f76832d..00000000000 --- a/examples/cors/pom.xml +++ /dev/null @@ -1,115 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../applications/se/pom.xml - - io.helidon.examples - helidon-examples-cors - Helidon Examples CORS SE - - - Basic illustration of CORS support in Helidon SE - - - - io.helidon.examples.cors.Main - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver.observe - helidon-webserver-observe - - - io.helidon.webserver.observe - helidon-webserver-observe-health - - - io.helidon.webserver.observe - helidon-webserver-observe-metrics - runtime - - - io.helidon.metrics - helidon-metrics-system-meters - runtime - - - io.helidon.config - helidon-config-yaml - - - io.helidon.http.media - helidon-http-media-jsonp - - - io.helidon.health - helidon-health-checks - - - io.helidon.logging - helidon-logging-jul - runtime - - - jakarta.json - jakarta.json-api - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - diff --git a/examples/cors/src/main/java/io/helidon/examples/cors/GreetService.java b/examples/cors/src/main/java/io/helidon/examples/cors/GreetService.java deleted file mode 100644 index 17271f98d45..00000000000 --- a/examples/cors/src/main/java/io/helidon/examples/cors/GreetService.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.cors; - -import java.util.Collections; - -import io.helidon.config.Config; -import io.helidon.http.Status; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; - -/** - * 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 HttpService { - - /** - * The config value for the key {@code greeting}. - */ - private String greeting; - - private static final JsonBuilderFactory JSON_BF = Json.createBuilderFactory(Collections.emptyMap()); - - GreetService() { - Config config = Config.global(); - this.greeting = config.get("app.greeting").asString().orElse("Ciao"); - } - - /** - * A service registers itself by updating the routine rules. - * - * @param rules the routing rules. - */ - @Override - public void routing(HttpRules 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().pathParameters().get("name"); - sendResponse(response, name); - } - - private void sendResponse(ServerResponse response, String name) { - GreetingMessage msg = new GreetingMessage(String.format("%s %s!", greeting, name)); - response.send(msg.forRest()); - } - - private void updateGreetingFromJson(JsonObject jo, ServerResponse response) { - - if (!jo.containsKey(GreetingMessage.JSON_LABEL)) { - JsonObject jsonErrorObject = JSON_BF.createObjectBuilder() - .add("error", "No greeting provided") - .build(); - response.status(Status.BAD_REQUEST_400) - .send(jsonErrorObject); - return; - } - - greeting = GreetingMessage.fromRest(jo).getMessage(); - response.status(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) { - JsonObject jo = request.content().as(JsonObject.class); - updateGreetingFromJson(jo, response); - } -} diff --git a/examples/cors/src/main/java/io/helidon/examples/cors/GreetingMessage.java b/examples/cors/src/main/java/io/helidon/examples/cors/GreetingMessage.java deleted file mode 100644 index 63b835069b6..00000000000 --- a/examples/cors/src/main/java/io/helidon/examples/cors/GreetingMessage.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2020, 2021 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.cors; - -import java.util.Collections; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import jakarta.json.JsonObjectBuilder; - -/** - * POJO for the greeting message exchanged between the server and the client. - */ -public class GreetingMessage { - - /** - * Label for tagging a {@code GreetingMessage} instance in JSON. - */ - public static final String JSON_LABEL = "greeting"; - - private static final JsonBuilderFactory JSON_BF = Json.createBuilderFactory(Collections.emptyMap()); - - private String message; - - /** - * Create a new greeting with the specified message content. - * - * @param message the message to store in the greeting - */ - public GreetingMessage(String message) { - this.message = message; - } - - /** - * Returns the message value. - * - * @return the message - */ - public String getMessage() { - return message; - } - - /** - * Sets the message value. - * - * @param message value to be set - */ - public void setMessage(String message) { - this.message = message; - } - - /** - * Converts a JSON object (typically read from the request payload) - * into a {@code GreetingMessage}. - * - * @param jsonObject the {@link JsonObject} to convert. - * @return {@code GreetingMessage} set according to the provided object - */ - public static GreetingMessage fromRest(JsonObject jsonObject) { - return new GreetingMessage(jsonObject.getString(JSON_LABEL)); - } - - /** - * Prepares a {@link JsonObject} corresponding to this instance. - * - * @return {@code JsonObject} representing this {@code GreetingMessage} instance - */ - public JsonObject forRest() { - JsonObjectBuilder builder = JSON_BF.createObjectBuilder(); - return builder.add(JSON_LABEL, message) - .build(); - } -} diff --git a/examples/cors/src/main/java/io/helidon/examples/cors/Main.java b/examples/cors/src/main/java/io/helidon/examples/cors/Main.java deleted file mode 100644 index 746b535fc8f..00000000000 --- a/examples/cors/src/main/java/io/helidon/examples/cors/Main.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.cors; - -import java.util.logging.Logger; - -import io.helidon.config.Config; -import io.helidon.cors.CrossOriginConfig; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.cors.CorsSupport; -import io.helidon.webserver.http.HttpRouting; - -/** - * Simple Hello World rest application. - */ -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) { - // load logging configuration - LogConfig.configureRuntime(); - - // initialize global config from default configuration - Config config = Config.create(); - Config.global(config); - - // Get webserver config from the "server" section of application.yaml - WebServerConfig.Builder builder = WebServer.builder(); - WebServer server = builder - .config(config.get("server")) - .routing(Main::routing) - .build() - .start(); - - System.out.println("WEB server is up! http://localhost:" + server.port() + "/greet"); - } - - /** - * Setup routing. - * - * @param routing routing builder - */ - static void routing(HttpRouting.Builder routing) { - - // Note: Add the CORS routing *before* registering the GreetService routing. - routing.register("/greet", corsSupportForGreeting(), new GreetService()); - } - - private static CorsSupport corsSupportForGreeting() { - Config config = Config.global(); - - // The default CorsSupport object (obtained using CorsSupport.create()) allows sharing for any HTTP method and with any - // origin. Using CorsSupport.create(Config) with a missing config node yields a default CorsSupport, which might not be - // what you want. This example warns if either expected config node is missing and then continues with the default. - - Config restrictiveConfig = config.get("restrictive-cors"); - if (!restrictiveConfig.exists()) { - Logger.getLogger(Main.class.getName()) - .warning("Missing restrictive config; continuing with default CORS support"); - } - - CorsSupport.Builder corsBuilder = CorsSupport.builder(); - - // Use possible overrides first. - config.get("cors") - .ifExists(c -> { - Logger.getLogger(Main.class.getName()).info("Using the override configuration"); - corsBuilder.mappedConfig(c); - }); - corsBuilder - .config(restrictiveConfig) // restricted sharing for PUT, DELETE - .addCrossOrigin(CrossOriginConfig.create()) // open sharing for other methods - .build(); - - return corsBuilder.build(); - } -} diff --git a/examples/cors/src/main/java/io/helidon/examples/cors/package-info.java b/examples/cors/src/main/java/io/helidon/examples/cors/package-info.java deleted file mode 100644 index 37ff772213f..00000000000 --- a/examples/cors/src/main/java/io/helidon/examples/cors/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2020 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 application showing CORS support in Helidon SE - *

      - * Start with {@link io.helidon.examples.cors.Main} class. - * - * @see io.helidon.examples.cors.Main - */ -package io.helidon.examples.cors; diff --git a/examples/cors/src/main/resources/META-INF/openapi.yml b/examples/cors/src/main/resources/META-INF/openapi.yml deleted file mode 100644 index 1d733567079..00000000000 --- a/examples/cors/src/main/resources/META-INF/openapi.yml +++ /dev/null @@ -1,79 +0,0 @@ -# -# Copyright (c) 2019, 2021 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. -# ---- -openapi: 3.0.0 -info: - title: Helidon SE Quickstart Example - description: A very simple application to reply with friendly greetings - version: 1.0.0 - -servers: - - url: http://localhost:8000 - description: Local test server - -paths: - /greet: - get: - summary: Returns a generic greeting - description: Greets the user generically - responses: - default: - description: Simple JSON containing the greeting - content: - application/json: - schema: - $ref: '#/components/schemas/GreetingMessage' - /greet/greeting: - put: - summary: Set the greeting prefix - description: Permits the client to set the prefix part of the greeting ("Hello") - requestBody: - description: Conveys the new greeting prefix to use in building greetings - content: - application/json: - schema: - $ref: '#/components/schemas/GreetingMessage' - examples: - greeting: - summary: Example greeting message to update - value: New greeting message - responses: - "200": - description: OK - content: - application/json: {} - /greet/{name}: - get: - summary: Returns a personalized greeting - parameters: - - name: name - in: path - required: true - schema: - type: string - responses: - default: - description: Simple JSON containing the greeting - content: - application/json: - schema: - $ref: '#/components/schemas/GreetingMessage' -components: - schemas: - GreetingMessage: - properties: - message: - type: string diff --git a/examples/cors/src/main/resources/application.yaml b/examples/cors/src/main/resources/application.yaml deleted file mode 100644 index b962b8f2a82..00000000000 --- a/examples/cors/src/main/resources/application.yaml +++ /dev/null @@ -1,34 +0,0 @@ -# -# Copyright (c) 2020, 2023 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. -# - -app: - greeting: "Hello" - -server: - port: 8080 - host: 0.0.0.0 - -restrictive-cors: - allow-origins: ["http://foo.com", "http://there.com"] - allow-methods: ["PUT", "DELETE"] - -# The example app uses the following for overriding other settings. -#cors: -# paths: -# - path-pattern: /greeting -# allow-origins: ["http://foo.com", "http://there.com", "http://other.com"] -# allow-methods: ["PUT", "DELETE"] - diff --git a/examples/cors/src/main/resources/logging.properties b/examples/cors/src/main/resources/logging.properties deleted file mode 100644 index 2c828e180b8..00000000000 --- a/examples/cors/src/main/resources/logging.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright (c) 2020, 2023 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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 - -# Uncomment the following to see CORS-related decision-making -# io.helidon.webserver.cors.level=FINE diff --git a/examples/cors/src/test/java/io/helidon/examples/cors/MainTest.java b/examples/cors/src/test/java/io/helidon/examples/cors/MainTest.java deleted file mode 100644 index 29ccc18f46f..00000000000 --- a/examples/cors/src/test/java/io/helidon/examples/cors/MainTest.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.cors; - -import java.util.List; -import java.util.Optional; - -import io.helidon.common.media.type.MediaTypes; -import io.helidon.config.Config; -import io.helidon.cors.CrossOriginConfig; -import io.helidon.http.Headers; -import io.helidon.http.WritableHeaders; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientRequest; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; - -import jakarta.json.JsonObject; -import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; - -import static io.helidon.http.HeaderNames.ACCESS_CONTROL_ALLOW_METHODS; -import static io.helidon.http.HeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN; -import static io.helidon.http.HeaderNames.ACCESS_CONTROL_REQUEST_METHOD; -import static io.helidon.http.HeaderNames.HOST; -import static io.helidon.http.HeaderNames.ORIGIN; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.hasItem; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.collection.IsEmptyCollection.empty; - -@SuppressWarnings("HttpUrlsUsage") -@TestMethodOrder(MethodOrderer.OrderAnnotation.class) -@ServerTest -public class MainTest { - - private final Http1Client client; - - MainTest(Http1Client client) { - this.client = client; - } - - @SetUpServer - public static void setup(WebServerConfig.Builder server) { - server.routing(Main::routing); - } - - @Order(1) // Make sure this runs before the greeting message changes so responses are deterministic. - @Test - public void testHelloWorld() { - try (Http1ClientResponse response = client.get("/greet") - .accept(MediaTypes.APPLICATION_JSON) - .request()) { - - assertThat(response.status().code(), is(200)); - - String payload = GreetingMessage.fromRest(response.entity().as(JsonObject.class)).getMessage(); - assertThat(payload, is("Hello World!")); - } - - try (Http1ClientResponse response = client.get("/greet/Joe") - .accept(MediaTypes.APPLICATION_JSON) - .request()) { - - assertThat(response.status().code(), is(200)); - - String payload = GreetingMessage.fromRest(response.entity().as(JsonObject.class)).getMessage(); - assertThat(payload, is("Hello Joe!")); - } - - try (Http1ClientResponse response = client.put("/greet/greeting") - .accept(MediaTypes.APPLICATION_JSON) - .submit(new GreetingMessage("Hola").forRest())) { - - assertThat(response.status().code(), is(204)); - } - - try (Http1ClientResponse response = client.get("/greet/Jose") - .accept(MediaTypes.APPLICATION_JSON) - .request()) { - - assertThat(response.status().code(), is(200)); - - String payload = GreetingMessage.fromRest(response.entity().as(JsonObject.class)).getMessage(); - assertThat(payload, is("Hola Jose!")); - } - - try (Http1ClientResponse response = client.get("/observe/health").request()) { - assertThat(response.status().code(), is(204)); - } - - try (Http1ClientResponse response = client.get("/observe/metrics").request()) { - assertThat(response.status().code(), is(200)); - } - } - - @Order(10) - // Run after the non-CORS tests (so the greeting is Hola) but before the CORS test that changes the greeting again. - @Test - void testAnonymousGreetWithCors() { - try (Http1ClientResponse response = client.get() - .path("/greet") - .accept(MediaTypes.APPLICATION_JSON) - .headers(it -> it - .set(ORIGIN, "http://foo.com") - .set(HOST, "here.com")) - .request()) { - - assertThat(response.status().code(), is(200)); - String payload = GreetingMessage.fromRest(response.entity().as(JsonObject.class)).getMessage(); - assertThat(payload, containsString("Hola World")); - Headers responseHeaders = response.headers(); - Optional allowOrigin = responseHeaders.value(ACCESS_CONTROL_ALLOW_ORIGIN); - assertThat("Expected CORS header " + CrossOriginConfig.ACCESS_CONTROL_ALLOW_ORIGIN + " is absent", - allowOrigin.isPresent(), is(true)); - assertThat(allowOrigin.get(), is("*")); - } - } - - @Order(11) // Run after the non-CORS tests but before other CORS tests. - @Test - void testGreetingChangeWithCors() { - // Send the pre-flight request and check the response. - WritableHeaders preFlightHeaders = WritableHeaders.create(); - try (Http1ClientResponse response = client.options() - .path("/greet/greeting") - .headers(it -> it - .set(ORIGIN, "http://foo.com") - .set(HOST, "here.com") - .set(ACCESS_CONTROL_REQUEST_METHOD, "PUT")) - .request()) { - response.headers().forEach(preFlightHeaders::add); - List allowMethods = preFlightHeaders.values(ACCESS_CONTROL_ALLOW_METHODS); - assertThat("pre-flight response does not include " + CrossOriginConfig.ACCESS_CONTROL_ALLOW_METHODS, - allowMethods, not(empty())); - assertThat(allowMethods, hasItem("PUT")); - List allowOrigins = preFlightHeaders.values(ACCESS_CONTROL_ALLOW_ORIGIN); - assertThat("pre-flight response does not include " + CrossOriginConfig.ACCESS_CONTROL_ALLOW_ORIGIN, - allowOrigins, not(empty())); - assertThat("Header " + CrossOriginConfig.ACCESS_CONTROL_ALLOW_ORIGIN - + " should contain '*' but does not; " + allowOrigins, - allowOrigins, hasItem("http://foo.com")); - } - - // Send the follow-up request. - GreetingMessage payload = new GreetingMessage("Cheers"); - try (Http1ClientResponse response = client.put("/greet/greeting") - .accept(MediaTypes.APPLICATION_JSON) - .headers(headers -> { - headers.set(ORIGIN, "http://foo.com"); - headers.set(HOST, "here.com"); - preFlightHeaders.forEach(headers::add); - }).submit(payload.forRest())) { - - assertThat(response.status().code(), is(204)); - List allowOrigins = preFlightHeaders.values(ACCESS_CONTROL_ALLOW_ORIGIN); - assertThat("Expected CORS header " + CrossOriginConfig.ACCESS_CONTROL_ALLOW_ORIGIN + " has no value(s)", - allowOrigins, not(empty())); - assertThat("Header " + CrossOriginConfig.ACCESS_CONTROL_ALLOW_ORIGIN - + " should contain '*' but does not; " + allowOrigins, - allowOrigins, hasItem("http://foo.com")); - } - } - - @Order(12) // Run after CORS test changes greeting to Cheers. - @Test - void testNamedGreetWithCors() { - try (Http1ClientResponse response = client.get() - .path("/greet/Maria") - .headers(headers -> headers - .set(ORIGIN, "http://foo.com") - .set(HOST, "here.com")) - .request()) { - assertThat("HTTP response", response.status().code(), is(200)); - String payload = GreetingMessage.fromRest(response.entity().as(JsonObject.class)).getMessage(); - assertThat(payload, containsString("Cheers Maria")); - Headers responseHeaders = response.headers(); - Optional allowOrigin = responseHeaders.value(ACCESS_CONTROL_ALLOW_ORIGIN); - assertThat("Expected CORS header " + CrossOriginConfig.ACCESS_CONTROL_ALLOW_ORIGIN + " is absent", - allowOrigin.isPresent(), is(true)); - assertThat(allowOrigin.get(), is("*")); - } - } - - @Order(100) // After all other tests, so we can rely on deterministic greetings. - @Test - void testGreetingChangeWithCorsAndOtherOrigin() { - Http1ClientRequest request = client.put() - .path("/greet/greeting"); - request.headers(headers -> { - headers.set(ORIGIN, "http://other.com"); - headers.set(HOST, "here.com"); - }); - - GreetingMessage payload = new GreetingMessage("Ahoy"); - try (Http1ClientResponse response = request.submit(payload.forRest())) { - // Result depends on whether we are using overrides or not. - boolean isOverriding = Config.create().get("cors").exists(); - assertThat("HTTP response3", response.status().code(), is(isOverriding ? 204 : 403)); - } - } -} diff --git a/examples/dbclient/README.md b/examples/dbclient/README.md deleted file mode 100644 index 5345384f745..00000000000 --- a/examples/dbclient/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# Helidon DB Client Examples - -Each subdirectory contains example code that highlights specific aspects of -Helidon DB Client. - -build examples in all folders (including the common folder) by -```shell -mvn package -``` -in the current folder. - ---- - -Pokémon, and Pokémon character names are trademarks of Nintendo. diff --git a/examples/dbclient/common/README.md b/examples/dbclient/common/README.md deleted file mode 100644 index 875f95c9232..00000000000 --- a/examples/dbclient/common/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# Common library for the DB Client examples - -shall be built using - -```shell - -mvn install - -``` - -to be accessible for the DB Client examples - -or make the whole pack of DB Client examples at the level above by - -```shell - -cd ../ -mvn package - -``` - -and get all DB Client examples compiled at once. \ No newline at end of file diff --git a/examples/dbclient/common/pom.xml b/examples/dbclient/common/pom.xml deleted file mode 100644 index 8998b0ab496..00000000000 --- a/examples/dbclient/common/pom.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples.dbclient - helidon-examples-dbclient-project - 4.1.0-SNAPSHOT - - - helidon-examples-dbclient-common - Helidon Examples DB Client Common - - - - io.helidon.dbclient - helidon-dbclient - - - io.helidon.http.media - helidon-http-media-jsonp - - - io.helidon.http.media - helidon-http-media-jsonb - - - io.helidon.webserver - helidon-webserver - - - jakarta.json - jakarta.json-api - - - diff --git a/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/AbstractPokemonService.java b/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/AbstractPokemonService.java deleted file mode 100644 index e25db73468c..00000000000 --- a/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/AbstractPokemonService.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.dbclient.common; - -import io.helidon.common.parameters.Parameters; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbTransaction; -import io.helidon.http.NotFoundException; -import io.helidon.webserver.http.Handler; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -import jakarta.json.JsonObject; - -/** - * Common methods that do not differ between JDBC and MongoDB. - */ -public abstract class AbstractPokemonService implements HttpService { - - private final DbClient dbClient; - - /** - * Create a new Pokémon service with a DB client. - * - * @param dbClient DB client to use for database operations - */ - protected AbstractPokemonService(DbClient dbClient) { - this.dbClient = dbClient; - } - - - @Override - public void routing(HttpRules rules) { - rules - .get("/", this::listPokemons) - // create new - .put("/", Handler.create(Pokemon.class, this::insertPokemon)) - // update existing - .post("/{name}/type/{type}", this::insertPokemonSimple) - // delete all - .delete("/", this::deleteAllPokemons) - // get one - .get("/{name}", this::getPokemon) - // delete one - .delete("/{name}", this::deletePokemon) - // example of transactional API (local transaction only!) - .put("/transactional", this::transactional) - // update one (TODO this is intentionally wrong - should use JSON request, just to make it simple we use path) - .put("/{name}/type/{type}", this::updatePokemonType); - } - - /** - * The DB client associated with this service. - * - * @return DB client instance - */ - protected DbClient dbClient() { - return dbClient; - } - - /** - * This method is left unimplemented to show differences between native statements that can be used. - * - * @param req Server request - * @param res Server response - */ - protected abstract void deleteAllPokemons(ServerRequest req, ServerResponse res); - - /** - * Insert new Pokémon with specified name. - * - * @param pokemon pokemon request entity - * @param res the server response - */ - private void insertPokemon(Pokemon pokemon, ServerResponse res) { - long count = dbClient.execute().createNamedInsert("insert2") - .namedParam(pokemon) - .execute(); - res.send("Inserted: " + count + " values"); - } - - /** - * Insert new Pokémon with specified name. - * - * @param req the server request - * @param res the server response - */ - private void insertPokemonSimple(ServerRequest req, ServerResponse res) { - Parameters params = req.path().pathParameters(); - // Test Pokémon POJO mapper - Pokemon pokemon = new Pokemon(params.get("name"), params.get("type")); - - long count = dbClient.execute().createNamedInsert("insert2") - .namedParam(pokemon) - .execute(); - res.send("Inserted: " + count + " values"); - } - - /** - * Get a single Pokémon by name. - * - * @param req server request - * @param res server response - */ - private void getPokemon(ServerRequest req, ServerResponse res) { - String pokemonName = req.path().pathParameters().get("name"); - res.send(dbClient.execute() - .namedGet("select-one", pokemonName) - .orElseThrow(() -> new NotFoundException("Pokemon " + pokemonName + " not found")) - .as(JsonObject.class)); - } - - /** - * Return JsonArray with all stored Pokémon. - * - * @param req the server request - * @param res the server response - */ - private void listPokemons(ServerRequest req, ServerResponse res) { - res.send(dbClient.execute() - .namedQuery("select-all") - .map(it -> it.as(JsonObject.class)) - .toList()); - } - - /** - * Update a Pokémon. - * Uses a transaction. - * - * @param req the server request - * @param res the server response - */ - private void updatePokemonType(ServerRequest req, ServerResponse res) { - Parameters params = req.path().pathParameters(); - String name = params.get("name"); - String type = params.get("type"); - long count = dbClient.execute() - .createNamedUpdate("update") - .addParam("name", name) - .addParam("type", type) - .execute(); - res.send("Updated: " + count + " values"); - } - - private void transactional(ServerRequest req, ServerResponse res) { - Pokemon pokemon = req.content().as(Pokemon.class); - DbTransaction tx = dbClient.transaction(); - try { - long count = tx.createNamedGet("select-for-update") - .namedParam(pokemon) - .execute() - .map(dbRow -> tx.createNamedUpdate("update") - .namedParam(pokemon) - .execute()) - .orElse(0L); - tx.commit(); - res.send("Updated " + count + " records"); - } catch (Throwable t) { - tx.rollback(); - throw t; - } - } - - /** - * Delete a Pokémon with specified name (key). - * - * @param req the server request - * @param res the server response - */ - private void deletePokemon(ServerRequest req, ServerResponse res) { - String name = req.path().pathParameters().get("name"); - long count = dbClient.execute().namedDelete("delete", name); - res.send("Deleted: " + count + " values"); - } -} diff --git a/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/Pokemon.java b/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/Pokemon.java deleted file mode 100644 index a176cca3419..00000000000 --- a/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/Pokemon.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.dbclient.common; - -import io.helidon.common.Reflected; - -/** - * POJO representing a very simplified Pokémon. - */ -@Reflected -public class Pokemon { - private String name; - private String type; - - /** - * Default constructor. - */ - public Pokemon() { - // JSON-B - } - - /** - * Create Pokémon with name and type. - * - * @param name name of the beast - * @param type type of the beast - */ - public Pokemon(String name, String type) { - this.name = name; - this.type = type; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } -} diff --git a/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/PokemonMapper.java b/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/PokemonMapper.java deleted file mode 100644 index 9ac733e2ea2..00000000000 --- a/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/PokemonMapper.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.dbclient.common; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import io.helidon.dbclient.DbColumn; -import io.helidon.dbclient.DbMapper; -import io.helidon.dbclient.DbRow; - -/** - * Maps database statements to {@link io.helidon.examples.dbclient.common.Pokemon} class. - */ -public class PokemonMapper implements DbMapper { - - @Override - public Pokemon read(DbRow row) { - DbColumn name = row.column("name"); - // we know that in mongo this is not true - if (null == name) { - name = row.column("_id"); - } - - DbColumn type = row.column("type"); - return new Pokemon(name.get(String.class), type.get(String.class)); - } - - @Override - public Map toNamedParameters(Pokemon value) { - Map map = new HashMap<>(1); - map.put("name", value.getName()); - map.put("type", value.getType()); - return map; - } - - @Override - public List toIndexedParameters(Pokemon value) { - List list = new ArrayList<>(2); - list.add(value.getName()); - list.add(value.getType()); - return list; - } -} diff --git a/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/PokemonMapperProvider.java b/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/PokemonMapperProvider.java deleted file mode 100644 index 7fd70e8e321..00000000000 --- a/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/PokemonMapperProvider.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.dbclient.common; - -import java.util.Optional; - -import io.helidon.common.Weight; -import io.helidon.dbclient.DbMapper; -import io.helidon.dbclient.spi.DbMapperProvider; - -/** - * Provides pokemon mappers. - */ -@Weight(100) -public class PokemonMapperProvider implements DbMapperProvider { - private static final PokemonMapper MAPPER = new PokemonMapper(); - - @SuppressWarnings("unchecked") - @Override - public Optional> mapper(Class type) { - if (type.equals(Pokemon.class)) { - return Optional.of((DbMapper) MAPPER); - } - return Optional.empty(); - } -} diff --git a/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/package-info.java b/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/package-info.java deleted file mode 100644 index 7e0afe5d8d0..00000000000 --- a/examples/dbclient/common/src/main/java/io/helidon/examples/dbclient/common/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2019, 2021 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. - */ -/** - * Common classes shared by JDBC and MongoDB examples. - */ -package io.helidon.examples.dbclient.common; diff --git a/examples/dbclient/common/src/main/resources/META-INF/services/io.helidon.dbclient.spi.DbMapperProvider b/examples/dbclient/common/src/main/resources/META-INF/services/io.helidon.dbclient.spi.DbMapperProvider deleted file mode 100644 index b292790974c..00000000000 --- a/examples/dbclient/common/src/main/resources/META-INF/services/io.helidon.dbclient.spi.DbMapperProvider +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2019, 2021 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. -# - -io.helidon.examples.dbclient.common.PokemonMapperProvider diff --git a/examples/dbclient/jdbc/README.md b/examples/dbclient/jdbc/README.md deleted file mode 100644 index 638dd6aed5f..00000000000 --- a/examples/dbclient/jdbc/README.md +++ /dev/null @@ -1,69 +0,0 @@ -# Helidon DB Client JDBC Example - -This example shows how to run Helidon DB Client over JDBC. - -Examples are given for H2, Oracle, or MySQL databases (note that MySQL is currently not supported for GraalVM native image) - -Uncomment the appropriate dependencies in the pom.xml for the desired database (H2, Oracle, or MySQL) and insure others are commented. - -Uncomment the appropriate configuration in the application.xml for the desired database (H2, Oracle, or MySQL) and insure others are commented. - -## Build - -``` -mvn package -``` - -This example may also be run as a GraalVM native image in which case can be built using the following: - -``` -mvn package -Pnative-image -``` - - -## Run - -This example requires a database. - -Instructions for H2 can be found here: http://www.h2database.com/html/cheatSheet.html - -Instructions for Oracle can be found here: https://github.com/oracle/docker-images/tree/master/OracleDatabase/SingleInstance - -MySQL can be run as a docker container with the following command: -``` -docker run --rm --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=pokemon -e MYSQL_USER=user -e MYSQL_PASSWORD=changeit mysql:5.7 -``` - - -Then run the application: - -``` -java -jar target/helidon-examples-dbclient-jdbc.jar -``` -or in the case of native image -``` -./target/helidon-examples-dbclient-jdbc -``` - -## Exercise - -The application has the following endpoints: - -- http://localhost:8079/db - the main business endpoint (see `curl` commands below) -- http://localhost:8079/metrics - the metrics endpoint (query adds application metrics) -- http://localhost:8079/health - has a custom database health check - -Application also connects to zipkin on default address. -The query operation adds database trace. - -`curl` commands: - -- `curl http://localhost:8079/db` - list all Pokemon in the database -- `curl -i -X PUT -d '{"name":"Squirtle","type":"water"}' http://localhost:8079/db` - add a new pokemon -- `curl http://localhost:8079/db/Squirtle` - get a single pokemon - -The application also supports update and delete - see `PokemonService.java` for bound endpoints. - ---- - -Pokémon, and Pokémon character names are trademarks of Nintendo. diff --git a/examples/dbclient/jdbc/pom.xml b/examples/dbclient/jdbc/pom.xml deleted file mode 100644 index 147818d766b..00000000000 --- a/examples/dbclient/jdbc/pom.xml +++ /dev/null @@ -1,211 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - - helidon-examples-dbclient-jdbc - Helidon Examples DB Client JDBC - - - io.helidon.examples.dbclient.jdbc.JdbcExampleMain - - - - - io.helidon.logging - helidon-logging-jul - runtime - - - io.helidon.tracing - helidon-tracing - - - io.helidon.tracing.providers - helidon-tracing-providers-zipkin - - - io.helidon.dbclient - helidon-dbclient-jdbc - - - io.helidon.dbclient - helidon-dbclient-tracing - - - io.helidon.dbclient - helidon-dbclient-metrics - - - io.helidon.dbclient - helidon-dbclient-metrics-hikari - - - io.helidon.dbclient - helidon-dbclient-health - - - io.helidon.dbclient - helidon-dbclient-jsonp - - - - - - io.helidon.integrations.db - ojdbc - - - - org.slf4j - slf4j-jdk14 - - - io.helidon.http.media - helidon-http-media-jsonb - - - io.helidon.webserver.observe - helidon-webserver-observe - - - io.helidon.webserver.observe - helidon-webserver-observe-tracing - - - io.helidon.config - helidon-config-yaml - - - io.helidon.examples.dbclient - helidon-examples-dbclient-common - ${project.version} - - - io.helidon.webserver.observe - helidon-webserver-observe-health - - - io.helidon.health - helidon-health-checks - - - io.helidon.webserver.observe - helidon-webserver-observe-metrics - runtime - - - io.helidon.metrics - helidon-metrics-system-meters - runtime - - - org.testcontainers - junit-jupiter - test - - - org.testcontainers - mysql - test - - - org.testcontainers - oracle-xe - - - com.mysql - mysql-connector-j - test - - - io.helidon.integrations.db - h2 - test - - - io.helidon.webclient - helidon-webclient - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.apache.maven.plugins - maven-failsafe-plugin - - - - integration-test - verify - - - - false - - - - - - - - diff --git a/examples/dbclient/jdbc/src/main/java/io/helidon/examples/dbclient/jdbc/JdbcExampleMain.java b/examples/dbclient/jdbc/src/main/java/io/helidon/examples/dbclient/jdbc/JdbcExampleMain.java deleted file mode 100644 index 1f9caabb06e..00000000000 --- a/examples/dbclient/jdbc/src/main/java/io/helidon/examples/dbclient/jdbc/JdbcExampleMain.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2019, 2024 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.dbclient.jdbc; - -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.health.DbClientHealthCheck; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.observe.ObserveFeature; -import io.helidon.webserver.observe.health.HealthObserver; - -/** - * Simple Hello World rest application. - */ -public final class JdbcExampleMain { - - /** - * Cannot be instantiated. - */ - private JdbcExampleMain() { - } - - /** - * Application main entry point. - * - * @param args command line arguments. - */ - public static void main(String[] args) { - // load logging configuration - LogConfig.configureRuntime(); - - // Prepare routing for the server - WebServer server = setupServer(WebServer.builder()); - - System.out.println("WEB server is up! http://localhost:" + server.port() + "/"); - } - - static WebServer setupServer(WebServerConfig.Builder builder) { - // By default, this will pick up application.yaml from the classpath - Config config = Config.global(); - - Config dbConfig = config.get("db"); - DbClient dbClient = DbClient.create(dbConfig); - - ObserveFeature observe = ObserveFeature.builder() - .config(config.get("server.features.observe")) - .addObserver(HealthObserver.builder() - .addCheck(DbClientHealthCheck.create(dbClient, dbConfig.get("health-check"))) - .build()) - .build(); - - return builder - .config(config.get("server")) - .addFeature(observe) - .routing(routing -> routing.register("/db", new PokemonService(dbClient))) - .build() - .start(); - } -} diff --git a/examples/dbclient/jdbc/src/main/java/io/helidon/examples/dbclient/jdbc/PokemonService.java b/examples/dbclient/jdbc/src/main/java/io/helidon/examples/dbclient/jdbc/PokemonService.java deleted file mode 100644 index 743357ebbef..00000000000 --- a/examples/dbclient/jdbc/src/main/java/io/helidon/examples/dbclient/jdbc/PokemonService.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.dbclient.jdbc; - -import io.helidon.dbclient.DbClient; -import io.helidon.examples.dbclient.common.AbstractPokemonService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -/** - * Example service using a database. - */ -public class PokemonService extends AbstractPokemonService { - - PokemonService(DbClient dbClient) { - super(dbClient); - - // dirty hack to prepare database for our POC - // MySQL init - long count = dbClient().execute().namedDml("create-table"); - System.out.println(count); - } - - @Override - protected void deleteAllPokemons(ServerRequest req, ServerResponse res) { - // this is to show how ad-hoc statements can be executed (and their naming in Tracing and Metrics) - long count = dbClient().execute().createDelete("DELETE FROM pokemons").execute(); - res.send("Deleted: " + count + " values"); - } -} diff --git a/examples/dbclient/jdbc/src/main/java/io/helidon/examples/dbclient/jdbc/package-info.java b/examples/dbclient/jdbc/src/main/java/io/helidon/examples/dbclient/jdbc/package-info.java deleted file mode 100644 index 13fdc00a70d..00000000000 --- a/examples/dbclient/jdbc/src/main/java/io/helidon/examples/dbclient/jdbc/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2019, 2021 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. - */ - -/** - * Quick start demo application. - */ -package io.helidon.examples.dbclient.jdbc; diff --git a/examples/dbclient/jdbc/src/main/resources/application.yaml b/examples/dbclient/jdbc/src/main/resources/application.yaml deleted file mode 100644 index cb175d49dcc..00000000000 --- a/examples/dbclient/jdbc/src/main/resources/application.yaml +++ /dev/null @@ -1,99 +0,0 @@ -# -# Copyright (c) 2019, 2024 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: 8079 - host: 0.0.0.0 - -tracing: - service: jdbc-db - -db: - source: jdbc - connection: - # - # H2 configuration - # - # Embedded mode (does not work with native image) -# url: jdbc:h2:~/test - # Server mode, run: docker run --rm --name h2 -p 9092:9082 -p 8082:8082 nemerosa/h2 -# url: "jdbc:h2:tcp://localhost:9092/~test" -# username: sa -# password: -# poolName: h2 - # - # MySQL configuration - # - # docker run --rm --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root \ - # -e MYSQL_DATABASE=pokemon -e MYSQL_USER=user -e MYSQL_PASSWORD=changeit mysql:5.7 -# url: jdbc:mysql://127.0.0.1:3306/pokemon?useSSL=false -# username: user -# password: changeit -# poolName: mysql - # - # Oracle configuration - # - # docker run --rm --name xe -p 1521:1521 -p 8888:8080 -e ORACLE_PWD=oracle wnameless/oracle-xe-11g-r2 - url: jdbc:oracle:thin:@localhost:1521/XE - username: system - password: oracle - poolName: oracle - initializationFailTimeout: -1 - connectionTimeout: 2000 - helidon: - pool-metrics: - enabled: true - # name prefix defaults to "db.pool." - if you have more than one client within a JVM, you may want to distinguish between them - name-prefix: "hikari." - health-check: - type: "query" - statementName: "health-check" - services: - tracing: - # would trace all statement names that start with select- - - statement-names: ["select-.*"] - # would trace all delete statements - - statement-types: ["DELETE"] - metrics: - - type: TIMER - errors: false - statement-names: ["select-.*"] - description: "Timer for successful selects" - - type: COUNTER - errors: false - statement-types: ["DELETE", "UPDATE", "INSERT", "DML"] - name-format: "db.counter.%s.success" - description: "Counter of successful DML statements" - - type: COUNTER - statement-types: ["DELETE", "UPDATE", "INSERT", "DML"] - success: false - name-format: "db.counter.%s.error" - description: "Counter of failed DML statements" - statements: - # Health check query statement for MySQL and H2 databases -# health-check: "SELECT 0" - # Health check query statement for Oracle database - health-check: "SELECT 1 FROM DUAL" - # Insert new pokemon - create-table: "CREATE TABLE pokemons (name VARCHAR(64) NOT NULL PRIMARY KEY, type VARCHAR(32))" - insert1: "INSERT INTO pokemons VALUES(?, ?)" - insert2: "INSERT INTO pokemons VALUES(:name, :type)" - select-by-type: "SELECT * FROM pokemons WHERE type = ?" - select-one: "SELECT * FROM pokemons WHERE name = ?" - select-all: "SELECT * FROM pokemons" - select-for-update: "SELECT * FROM pokemons WHERE name = :name for UPDATE" - update: "UPDATE pokemons SET type = :type WHERE name = :name" - delete: "DELETE FROM pokemons WHERE name = ?" diff --git a/examples/dbclient/jdbc/src/main/resources/logging.properties b/examples/dbclient/jdbc/src/main/resources/logging.properties deleted file mode 100644 index 550b8d9a48c..00000000000 --- a/examples/dbclient/jdbc/src/main/resources/logging.properties +++ /dev/null @@ -1,35 +0,0 @@ -# -# Copyright (c) 2019, 2024 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.HelidonConsoleHandler - -# Global default logging level. Can be overridden by specific handlers and loggers -.level=INFO - -# Helidon Web Server has a custom log formatter that extends SimpleFormatter. -# It replaces "!thread!" with the current thread name -io.helidon.logging.jul.HelidonConsoleHandler.level=ALL -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 - -#Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.common.level=INFO diff --git a/examples/dbclient/jdbc/src/test/java/io/helidon/examples/dbclient/jdbc/AbstractPokemonServiceTest.java b/examples/dbclient/jdbc/src/test/java/io/helidon/examples/dbclient/jdbc/AbstractPokemonServiceTest.java deleted file mode 100644 index 384e7daa133..00000000000 --- a/examples/dbclient/jdbc/src/test/java/io/helidon/examples/dbclient/jdbc/AbstractPokemonServiceTest.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2023, 2024 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.dbclient.jdbc; - -import java.util.List; -import java.util.Map; - -import io.helidon.http.Status; -import io.helidon.http.media.jsonp.JsonpSupport; -import io.helidon.webclient.api.ClientResponseTyped; -import io.helidon.webclient.api.WebClient; -import io.helidon.webserver.WebServer; - -import jakarta.json.Json; -import jakarta.json.JsonArray; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - -abstract class AbstractPokemonServiceTest { - private static final JsonBuilderFactory JSON_FACTORY = Json.createBuilderFactory(Map.of()); - - private static WebServer server; - private static WebClient client; - - static void beforeAll() { - server = JdbcExampleMain.setupServer(WebServer.builder()); - client = WebClient.create(config -> config.baseUri("http://localhost:" + server.port()) - .addMediaSupport(JsonpSupport.create())); - } - - static void afterAll() { - if (server != null && server.isRunning()) { - server.stop(); - } - } - - @Test - void testListAndDeleteAllPokemons() { - List names = listAllPokemons(); - assertThat(names.isEmpty(), is(true)); - - String endpoint = String.format("/db/%s/type/%s", "Raticate", 1); - ClientResponseTyped response = client.post(endpoint).request(String.class); - assertThat(response.status(), is(Status.OK_200)); - - names = listAllPokemons(); - assertThat(names.size(), is(1)); - assertThat(names.getFirst(), is("Raticate")); - - response = client.delete("/db").request(String.class); - assertThat(response.status(), is(Status.OK_200)); - - names = listAllPokemons(); - assertThat(names.isEmpty(), is(true)); - } - - @Test - void testAddUpdateDeletePokemon() { - ClientResponseTyped response; - ClientResponseTyped jsonResponse; - JsonObject pokemon = JSON_FACTORY.createObjectBuilder() - .add("type", 1) - .add("name", "Raticate") - .build(); - - // Add new pokemon - response = client.put("/db").submit(pokemon, String.class); - assertThat(response.entity(), is("Inserted: 1 values")); - - // Get the new pokemon added - jsonResponse = client.get("/db/Raticate").request(JsonObject.class); - assertThat(jsonResponse.status(), is(Status.OK_200)); - assertThat(getName(jsonResponse.entity()), is("Raticate")); - assertThat(getType(jsonResponse.entity()), is("1")); - - // Update pokemon - response = client.put("/db/Raticate/type/2").request(String.class); - assertThat(response.status(), is(Status.OK_200)); - - // Verify updated pokemon - jsonResponse = client.get("/db/Raticate").request(JsonObject.class); - assertThat(jsonResponse.status(), is(Status.OK_200)); - assertThat(getName(jsonResponse.entity()), is("Raticate")); - assertThat(getType(jsonResponse.entity()), is("2")); - - // Delete Pokemon - response = client.delete("/db/Raticate").request(String.class); - assertThat(response.status(), is(Status.OK_200)); - - // Verify pokemon is correctly deleted - response = client.get("/db/Raticate").request(String.class); - assertThat(response.status(), is(Status.NOT_FOUND_404)); - } - - private List listAllPokemons() { - ClientResponseTyped response = client.get("/db").request(JsonArray.class); - assertThat(response.status(), is(Status.OK_200)); - return response.entity().stream().map(e -> getName(e.asJsonObject())).toList(); - } - - private String getName(JsonObject json) { - return json.containsKey("name") - ? json.getString("name") - : json.getString("NAME"); - } - - private String getType(JsonObject json) { - return json.containsKey("type") - ? json.getString("type") - : json.getString("TYPE"); - } -} diff --git a/examples/dbclient/jdbc/src/test/java/io/helidon/examples/dbclient/jdbc/PokemonServiceH2IT.java b/examples/dbclient/jdbc/src/test/java/io/helidon/examples/dbclient/jdbc/PokemonServiceH2IT.java deleted file mode 100644 index 7f5c8dee143..00000000000 --- a/examples/dbclient/jdbc/src/test/java/io/helidon/examples/dbclient/jdbc/PokemonServiceH2IT.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2023, 2024 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.dbclient.jdbc; - -import java.util.Map; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.testcontainers.containers.GenericContainer; -import org.testcontainers.containers.wait.strategy.Wait; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; -import org.testcontainers.utility.DockerImageName; - -import static io.helidon.config.ConfigSources.classpath; - -@Testcontainers(disabledWithoutDocker = true) -class PokemonServiceH2IT extends AbstractPokemonServiceTest { - private static final DockerImageName H2_IMAGE = DockerImageName.parse("nemerosa/h2"); - - @Container - static GenericContainer container = new GenericContainer<>(H2_IMAGE) - .withExposedPorts(9082) - .waitingFor(Wait.forLogMessage("(.*)Web Console server running at(.*)", 1)); - - @BeforeAll - static void start() { - String url = String.format("jdbc:h2:tcp://localhost:%s/~./test", container.getMappedPort(9082)); - Config.global(Config.builder() - .addSource(ConfigSources.create(Map.of("db.connection.url", url))) - .addSource(classpath("application-h2-test.yaml")) - .build()); - beforeAll(); - } - - @AfterAll - static void stop() { - afterAll(); - } -} diff --git a/examples/dbclient/jdbc/src/test/java/io/helidon/examples/dbclient/jdbc/PokemonServiceMySQLIT.java b/examples/dbclient/jdbc/src/test/java/io/helidon/examples/dbclient/jdbc/PokemonServiceMySQLIT.java deleted file mode 100644 index eee51c64b23..00000000000 --- a/examples/dbclient/jdbc/src/test/java/io/helidon/examples/dbclient/jdbc/PokemonServiceMySQLIT.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2023, 2024 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.dbclient.jdbc; - -import java.util.Map; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.testcontainers.containers.MySQLContainer; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; - -import static io.helidon.config.ConfigSources.classpath; - -@Testcontainers(disabledWithoutDocker = true) -class PokemonServiceMySQLIT extends AbstractPokemonServiceTest { - - @Container - static MySQLContainer container = new MySQLContainer<>("mysql:8.0.36") - .withUsername("user") - .withPassword("changeit") - .withNetworkAliases("mysql") - .withDatabaseName("pokemon"); - - @BeforeAll - static void start() { - Config.global(Config.builder() - .addSource(ConfigSources.create(Map.of("db.connection.url", container.getJdbcUrl()))) - .addSource(classpath("application-mysql-test.yaml")) - .build()); - beforeAll(); - } - - @AfterAll - static void stop() { - afterAll(); - } - -} diff --git a/examples/dbclient/jdbc/src/test/java/io/helidon/examples/dbclient/jdbc/PokemonServiceOracleIT.java b/examples/dbclient/jdbc/src/test/java/io/helidon/examples/dbclient/jdbc/PokemonServiceOracleIT.java deleted file mode 100644 index a37525049f5..00000000000 --- a/examples/dbclient/jdbc/src/test/java/io/helidon/examples/dbclient/jdbc/PokemonServiceOracleIT.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2024 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.dbclient.jdbc; - -import java.util.Map; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.testcontainers.containers.OracleContainer; -import org.testcontainers.containers.wait.strategy.Wait; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; -import org.testcontainers.utility.DockerImageName; - -import static io.helidon.config.ConfigSources.classpath; - -@Testcontainers(disabledWithoutDocker = true) -public class PokemonServiceOracleIT extends AbstractPokemonServiceTest { - - private static final DockerImageName image = DockerImageName.parse("wnameless/oracle-xe-11g-r2") - .asCompatibleSubstituteFor("gvenzl/oracle-xe"); - - @Container - static OracleContainer container = new OracleContainer(image) - .withExposedPorts(1521, 8080) - .withDatabaseName("XE") - .usingSid() - .waitingFor(Wait.forListeningPorts(1521, 8080)); - - @BeforeAll - static void start() { - Config.global(Config.builder() - .addSource(ConfigSources.create(Map.of("db.connection.url", container.getJdbcUrl()))) - .addSource(classpath("application-oracle-test.yaml")) - .build()); - beforeAll(); - } - - @AfterAll - static void stop() { - afterAll(); - } -} diff --git a/examples/dbclient/jdbc/src/test/resources/application-h2-test.yaml b/examples/dbclient/jdbc/src/test/resources/application-h2-test.yaml deleted file mode 100644 index f75ba554c40..00000000000 --- a/examples/dbclient/jdbc/src/test/resources/application-h2-test.yaml +++ /dev/null @@ -1,72 +0,0 @@ -# -# Copyright (c) 2024 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: 8079 - host: 0.0.0.0 - -tracing: - service: jdbc-db - -db: - source: jdbc - connection: - username: sa - password: - poolName: h2 - initializationFailTimeout: -1 - connectionTimeout: 2000 - helidon: - pool-metrics: - enabled: true - # name prefix defaults to "db.pool." - if you have more than one client within a JVM, you may want to distinguish between them - name-prefix: "hikari." - health-check: - type: "query" - statementName: "health-check" - services: - tracing: - # would trace all statement names that start with select- - - statement-names: ["select-.*"] - # would trace all delete statements - - statement-types: ["DELETE"] - metrics: - - type: TIMER - errors: false - statement-names: ["select-.*"] - description: "Timer for successful selects" - - type: COUNTER - errors: false - statement-types: ["DELETE", "UPDATE", "INSERT", "DML"] - name-format: "db.counter.%s.success" - description: "Counter of successful DML statements" - - type: COUNTER - statement-types: ["DELETE", "UPDATE", "INSERT", "DML"] - success: false - name-format: "db.counter.%s.error" - description: "Counter of failed DML statements" - statements: - health-check: "SELECT 0" - # Insert new pokemon - create-table: "CREATE TABLE pokemons (name VARCHAR(64) NOT NULL PRIMARY KEY, type VARCHAR(32))" - insert1: "INSERT INTO pokemons VALUES(?, ?)" - insert2: "INSERT INTO pokemons VALUES(:name, :type)" - select-by-type: "SELECT * FROM pokemons WHERE type = ?" - select-one: "SELECT * FROM pokemons WHERE name = ?" - select-all: "SELECT * FROM pokemons" - select-for-update: "SELECT * FROM pokemons WHERE name = :name for UPDATE" - update: "UPDATE pokemons SET type = :type WHERE name = :name" - delete: "DELETE FROM pokemons WHERE name = ?" diff --git a/examples/dbclient/jdbc/src/test/resources/application-mysql-test.yaml b/examples/dbclient/jdbc/src/test/resources/application-mysql-test.yaml deleted file mode 100644 index 8bf82887909..00000000000 --- a/examples/dbclient/jdbc/src/test/resources/application-mysql-test.yaml +++ /dev/null @@ -1,72 +0,0 @@ -# -# Copyright (c) 2024 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: 8079 - host: 0.0.0.0 - -tracing: - service: jdbc-db - -db: - source: jdbc - connection: - username: user - password: changeit - poolName: mysql - initializationFailTimeout: -1 - connectionTimeout: 2000 - helidon: - pool-metrics: - enabled: true - # name prefix defaults to "db.pool." - if you have more than one client within a JVM, you may want to distinguish between them - name-prefix: "hikari." - health-check: - type: "query" - statementName: "health-check" - services: - tracing: - # would trace all statement names that start with select- - - statement-names: ["select-.*"] - # would trace all delete statements - - statement-types: ["DELETE"] - metrics: - - type: TIMER - errors: false - statement-names: ["select-.*"] - description: "Timer for successful selects" - - type: COUNTER - errors: false - statement-types: ["DELETE", "UPDATE", "INSERT", "DML"] - name-format: "db.counter.%s.success" - description: "Counter of successful DML statements" - - type: COUNTER - statement-types: ["DELETE", "UPDATE", "INSERT", "DML"] - success: false - name-format: "db.counter.%s.error" - description: "Counter of failed DML statements" - statements: - health-check: "SELECT 0" - # Insert new pokemon - create-table: "CREATE TABLE pokemons (name VARCHAR(64) NOT NULL PRIMARY KEY, type VARCHAR(32))" - insert1: "INSERT INTO pokemons VALUES(?, ?)" - insert2: "INSERT INTO pokemons VALUES(:name, :type)" - select-by-type: "SELECT * FROM pokemons WHERE type = ?" - select-one: "SELECT * FROM pokemons WHERE name = ?" - select-all: "SELECT * FROM pokemons" - select-for-update: "SELECT * FROM pokemons WHERE name = :name for UPDATE" - update: "UPDATE pokemons SET type = :type WHERE name = :name" - delete: "DELETE FROM pokemons WHERE name = ?" diff --git a/examples/dbclient/jdbc/src/test/resources/application-oracle-test.yaml b/examples/dbclient/jdbc/src/test/resources/application-oracle-test.yaml deleted file mode 100644 index dd713c0558d..00000000000 --- a/examples/dbclient/jdbc/src/test/resources/application-oracle-test.yaml +++ /dev/null @@ -1,74 +0,0 @@ -# -# Copyright (c) 2024 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: 8079 - host: 0.0.0.0 - -tracing: - service: jdbc-db - -db: - source: jdbc - connection: - username: "system" - password: "oracle" - initializationFailTimeout: -1 - connectionTimeout: 2000 - helidon: - pool-metrics: - enabled: true - # name prefix defaults to "db.pool." - if you have more than one client within a JVM, you may want to distinguish between them - name-prefix: "hikari." - health-check: - type: "query" - statementName: "health-check" - services: - tracing: - # would trace all statement names that start with select- - - statement-names: ["select-.*"] - # would trace all delete statements - - statement-types: ["DELETE"] - metrics: - - type: TIMER - errors: false - statement-names: ["select-.*"] - description: "Timer for successful selects" - - type: COUNTER - errors: false - statement-types: ["DELETE", "UPDATE", "INSERT", "DML"] - name-format: "db.counter.%s.success" - description: "Counter of successful DML statements" - - type: COUNTER - statement-types: ["DELETE", "UPDATE", "INSERT", "DML"] - success: false - name-format: "db.counter.%s.error" - description: "Counter of failed DML statements" - statements: - # Health check query statement for MySQL and H2 databases - # health-check: "SELECT 0" - # Health check query statement for Oracle database - health-check: "SELECT 1 FROM DUAL" - # Insert new pokemon - create-table: "CREATE TABLE pokemons (name VARCHAR(64) NOT NULL PRIMARY KEY, type VARCHAR(32))" - insert1: "INSERT INTO pokemons VALUES(?, ?)" - insert2: "INSERT INTO pokemons VALUES(:name, :type)" - select-by-type: "SELECT * FROM pokemons WHERE type = ?" - select-one: "SELECT * FROM pokemons WHERE name = ?" - select-all: "SELECT * FROM pokemons" - select-for-update: "SELECT * FROM pokemons WHERE name = :name for UPDATE" - update: "UPDATE pokemons SET type = :type WHERE name = :name" - delete: "DELETE FROM pokemons WHERE name = ?" diff --git a/examples/dbclient/mongodb/README.md b/examples/dbclient/mongodb/README.md deleted file mode 100644 index 307cab3a83a..00000000000 --- a/examples/dbclient/mongodb/README.md +++ /dev/null @@ -1,50 +0,0 @@ -# Helidon DB Client mongoDB Example - -This example shows how to run Helidon DB over mongoDB. - - -## Build - -``` -mvn package -``` - -## Run - -This example requires a mongoDB database, start it using docker: - -``` -docker run --rm --name mongo -p 27017:27017 mongo -``` - -Then run the application: - -``` -java -jar target/helidon-examples-dbclient-mongodb.jar -``` - - -## Exercise - -The application has the following endpoints: - -- http://localhost:8079/db - the main business endpoint (see `curl` commands below) -- http://localhost:8079/metrics - the metrics endpoint (query adds application metrics) -- http://localhost:8079/health - has a custom database health check - -Application also connects to zipkin on default address. -The query operation adds database trace. - -`curl` commands: - -- `curl http://localhost:8079/db` - list all Pokemon in the database -- `curl -i -X PUT -H 'Content-type: application/json' -d '{"name":"Squirtle","type":"water"}' http://localhost:8079/db` - add a new pokemon -- `curl http://localhost:8079/db/Squirtle` - get a single pokemon -- `curl -i -X DELETE http://localhost:8079/db/Squirtle` - delete a single pokemon -- `curl -i -X DELETE http://localhost:8079/db` - delete all pokemon - -The application also supports update and delete - see `PokemonService.java` for bound endpoints. - ---- - -Pokémon, and Pokémon character names are trademarks of Nintendo. diff --git a/examples/dbclient/mongodb/pom.xml b/examples/dbclient/mongodb/pom.xml deleted file mode 100644 index 525b29db774..00000000000 --- a/examples/dbclient/mongodb/pom.xml +++ /dev/null @@ -1,155 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - - helidon-examples-dbclient-mongodb - Helidon Examples DB Client MongoDB - - - io.helidon.examples.dbclient.mongo.MongoDbExampleMain - - - - - io.helidon.common - helidon-common - - - io.helidon.common - helidon-common-mapper - - - io.helidon.dbclient - helidon-dbclient-mongodb - - - io.helidon.dbclient - helidon-dbclient-tracing - - - io.helidon.dbclient - helidon-dbclient-metrics - - - io.helidon.dbclient - helidon-dbclient-health - - - io.helidon.dbclient - helidon-dbclient-jsonp - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver.observe - helidon-webserver-observe - - - io.helidon.webserver.observe - helidon-webserver-observe-tracing - - - io.helidon.metrics - helidon-metrics-api - - - io.helidon.webserver.observe - helidon-webserver-observe-metrics - runtime - - - io.helidon.metrics - helidon-metrics-system-meters - runtime - - - io.helidon.tracing - helidon-tracing - - - io.helidon.tracing.providers - helidon-tracing-providers-zipkin - - - io.helidon.config - helidon-config-yaml - - - io.helidon.examples.dbclient - helidon-examples-dbclient-common - ${project.version} - - - io.helidon.logging - helidon-logging-jul - runtime - - - org.testcontainers - junit-jupiter - test - - - org.testcontainers - mongodb - test - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.apache.maven.plugins - maven-failsafe-plugin - - - - integration-test - verify - - - - - - - diff --git a/examples/dbclient/mongodb/src/main/java/io/helidon/examples/dbclient/mongo/MongoDbExampleMain.java b/examples/dbclient/mongodb/src/main/java/io/helidon/examples/dbclient/mongo/MongoDbExampleMain.java deleted file mode 100644 index 9df1a786700..00000000000 --- a/examples/dbclient/mongodb/src/main/java/io/helidon/examples/dbclient/mongo/MongoDbExampleMain.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.dbclient.mongo; - -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbStatementType; -import io.helidon.dbclient.metrics.DbClientMetrics; -import io.helidon.dbclient.tracing.DbClientTracing; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.http.HttpRouting; - -/** - * Simple Hello World rest application. - */ -public final class MongoDbExampleMain { - - /** - * Cannot be instantiated. - */ - private MongoDbExampleMain() { - } - - /** - * Application main entry point. - * - * @param args command line arguments. - */ - public static void main(String[] args) { - startServer(); - } - - /** - * Start the server. - * - * @return the created {@link WebServer} instance - */ - static WebServer startServer() { - - // load logging configuration - LogConfig.configureRuntime(); - - WebServer server = setupServer(WebServer.builder()); - - System.out.println("WEB server is up! http://localhost:" + server.port() + "/"); - return server; - } - - static WebServer setupServer(WebServerConfig.Builder builder) { - // By default, this will pick up application.yaml from the classpath - Config config = Config.create(); - - return builder.routing(routing -> routing(routing, config)) - .config(config.get("server")) - .build() - .start(); - } - - /** - * Setup routing. - * - * @param config configuration of this server - */ - private static void routing(HttpRouting.Builder routing, Config config) { - Config dbConfig = config.get("db"); - - DbClient dbClient = DbClient.builder(dbConfig) - // add an interceptor to named statement(s) - .addService(DbClientMetrics.counter().statementNames("select-all", "select-one")) - // add an interceptor to statement type(s) - .addService(DbClientMetrics.timer() - .statementTypes(DbStatementType.DELETE, DbStatementType.UPDATE, DbStatementType.INSERT)) - // add an interceptor to all statements - .addService(DbClientTracing.create()) - .build(); - - routing.register("/db", new PokemonService(dbClient)); - } -} diff --git a/examples/dbclient/mongodb/src/main/java/io/helidon/examples/dbclient/mongo/PokemonService.java b/examples/dbclient/mongodb/src/main/java/io/helidon/examples/dbclient/mongo/PokemonService.java deleted file mode 100644 index ee286ff8c94..00000000000 --- a/examples/dbclient/mongodb/src/main/java/io/helidon/examples/dbclient/mongo/PokemonService.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.dbclient.mongo; - -import io.helidon.dbclient.DbClient; -import io.helidon.examples.dbclient.common.AbstractPokemonService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -/** - * A simple service to greet you. Examples: - *

      - * Get default greeting message: - * curl -X GET {@code http://localhost:8080/greet} - *

      - * Get greeting message for Joe: - * curl -X GET {@code http://localhost:8080/greet/Joe} - *

      - * Change greeting - * curl -X PUT {@code http://localhost:8080/greet/greeting/Hola} - *

      - * The message is returned as a JSON object - */ - -public class PokemonService extends AbstractPokemonService { - - PokemonService(DbClient dbClient) { - super(dbClient); - } - - @Override - protected void deleteAllPokemons(ServerRequest req, ServerResponse res) { - long count = dbClient().execute().createNamedDelete("delete-all") - .execute(); - res.send("Deleted: " + count + " values"); - } -} diff --git a/examples/dbclient/mongodb/src/main/java/io/helidon/examples/dbclient/mongo/package-info.java b/examples/dbclient/mongodb/src/main/java/io/helidon/examples/dbclient/mongo/package-info.java deleted file mode 100644 index 79a3b9e0c07..00000000000 --- a/examples/dbclient/mongodb/src/main/java/io/helidon/examples/dbclient/mongo/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2019, 2021 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. - */ - -/** - * Quick start demo application. - */ -package io.helidon.examples.dbclient.mongo; diff --git a/examples/dbclient/mongodb/src/main/resources/application.yaml b/examples/dbclient/mongodb/src/main/resources/application.yaml deleted file mode 100644 index 14356c5e88e..00000000000 --- a/examples/dbclient/mongodb/src/main/resources/application.yaml +++ /dev/null @@ -1,76 +0,0 @@ -# -# Copyright (c) 2019, 2023 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: 8079 - host: 0.0.0.0 - -tracing: - service: "mongo-db" - -# docker run --rm --name mongo -p 27017:27017 mongo -db: - source: "mongoDb" - connection: - url: "mongodb://127.0.0.1:27017/pokemon" - health-check: - type: "query" - statementName: "health-check" - statements: - # Health check statement. HealthCheck statement type must be query. - health-check: '{ - "operation": "command", - "query": { ping: 1 } - }' - # Insert operation contains collection name, operation type and data to be inserted. - # Name variable is stored as MongoDB primary key attribute _id - insert2: '{ - "collection": "pokemons", - "value": { - "_id": $name, - "type": $type - } - }' - select-all: '{ - "collection": "pokemons", - "query": {} - }' - select-one: '{ - "collection": "pokemons", - "query": { - "_id": ? - } - }' - delete-all: '{ - "collection": "pokemons", - "operation": "delete" - }' - update: '{ - "collection": "pokemons", - "query": { - "_id": $name - }, - "value": { - $set: { "type": $type } - } - }' - delete: '{ - "collection": "pokemons", - "query": { - "_id": ? - } - }' - diff --git a/examples/dbclient/mongodb/src/main/resources/logging.properties b/examples/dbclient/mongodb/src/main/resources/logging.properties deleted file mode 100644 index 550b8d9a48c..00000000000 --- a/examples/dbclient/mongodb/src/main/resources/logging.properties +++ /dev/null @@ -1,35 +0,0 @@ -# -# Copyright (c) 2019, 2024 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.HelidonConsoleHandler - -# Global default logging level. Can be overridden by specific handlers and loggers -.level=INFO - -# Helidon Web Server has a custom log formatter that extends SimpleFormatter. -# It replaces "!thread!" with the current thread name -io.helidon.logging.jul.HelidonConsoleHandler.level=ALL -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 - -#Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.common.level=INFO diff --git a/examples/dbclient/mongodb/src/test/java/io/helidon/examples/dbclient/mongo/MainIT.java b/examples/dbclient/mongodb/src/test/java/io/helidon/examples/dbclient/mongo/MainIT.java deleted file mode 100644 index 109c11e9407..00000000000 --- a/examples/dbclient/mongodb/src/test/java/io/helidon/examples/dbclient/mongo/MainIT.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 2023 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.dbclient.mongo; - -import java.util.List; -import java.util.Map; - -import io.helidon.config.Config; -import io.helidon.http.Status; -import io.helidon.http.media.jsonb.JsonbSupport; -import io.helidon.http.media.jsonp.JsonpSupport; -import io.helidon.webclient.api.ClientResponseTyped; -import io.helidon.webclient.api.WebClient; -import io.helidon.webserver.WebServer; - -import jakarta.json.Json; -import jakarta.json.JsonArray; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.testcontainers.containers.MongoDBContainer; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - -@Testcontainers(disabledWithoutDocker = true) -public class MainIT { - - @Container - static final MongoDBContainer container = new MongoDBContainer("mongo") - .withExposedPorts(27017); - - private static final JsonBuilderFactory JSON_FACTORY = Json.createBuilderFactory(Map.of()); - private static final String CONNECTION_URL_KEY = "db.connection.url"; - - private static WebServer server; - private static WebClient client; - - @BeforeAll - static void beforeAll() { - String url = String.format("mongodb://127.0.0.1:%s/pokemon", container.getMappedPort(27017)); - System.setProperty(CONNECTION_URL_KEY, url); - server = MongoDbExampleMain.setupServer(WebServer.builder()); - client = WebClient.create(config -> config.baseUri("http://localhost:" + server.port()) - .addMediaSupport(JsonbSupport.create(Config.create())) - .addMediaSupport(JsonpSupport.create())); - } - - @AfterAll - static void afterAll() { - if (server != null && server.isRunning()) { - server.stop(); - } - System.clearProperty(CONNECTION_URL_KEY); - } - - @Test - void testListAndDeleteAllPokemons() { - List names = listAllPokemons(); - assertThat(names.isEmpty(), is(true)); - - String endpoint = String.format("/db/%s/type/%s", "Raticate", 1); - ClientResponseTyped response = client.post(endpoint).request(String.class); - assertThat(response.status(), is(Status.OK_200)); - - names = listAllPokemons(); - assertThat(names.size(), is(1)); - assertThat(names.getFirst(), is("Raticate")); - - response = client.delete("/db").request(String.class); - assertThat(response.status(), is(Status.OK_200)); - - names = listAllPokemons(); - assertThat(names.isEmpty(), is(true)); - } - - @Test - void testAddUpdateDeletePokemon() { - ClientResponseTyped response; - ClientResponseTyped jsonResponse; - JsonObject pokemon = JSON_FACTORY.createObjectBuilder() - .add("type", 1) - .add("name", "Raticate") - .build(); - - // Add new pokemon - response = client.put("/db").submit(pokemon, String.class); - assertThat(response.entity(), is("Inserted: 1 values")); - - // Get the new pokemon added - jsonResponse = client.get("/db/Raticate").request(JsonObject.class); - assertThat(jsonResponse.status(), is(Status.OK_200)); - assertThat(jsonResponse.entity().getString("_id"), is("Raticate")); - assertThat(jsonResponse.entity().getString("type"), is("1")); - - // Update pokemon - response = client.put("/db/Raticate/type/2").request(String.class); - assertThat(response.status(), is(Status.OK_200)); - - // Verify updated pokemon - jsonResponse = client.get("/db/Raticate").request(JsonObject.class); - assertThat(jsonResponse.status(), is(Status.OK_200)); - assertThat(jsonResponse.entity().getString("_id"), is("Raticate")); - assertThat(jsonResponse.entity().getString("type"), is("2")); - - // Delete Pokemon - response = client.delete("/db/Raticate").request(String.class); - assertThat(response.status(), is(Status.OK_200)); - - // Verify pokemon is correctly deleted - response = client.get("/db/Raticate").request(String.class); - assertThat(response.status(), is(Status.NOT_FOUND_404)); - } - - private List listAllPokemons() { - ClientResponseTyped response = client.get("/db").request(JsonArray.class); - assertThat(response.status(), is(Status.OK_200)); - return response.entity().stream().map(e -> e.asJsonObject().getString("_id")).toList(); - } -} diff --git a/examples/dbclient/pokemons/README.md b/examples/dbclient/pokemons/README.md deleted file mode 100644 index 807dc1ae664..00000000000 --- a/examples/dbclient/pokemons/README.md +++ /dev/null @@ -1,141 +0,0 @@ -# Helidon DB Client Pokémon Example with JDBC - -This example shows how to run Helidon DB Client over JDBC. - -Application provides REST service endpoint with CRUD operations on Pokémons -database. - -## Database - -Database model contains two tables: - -**Types** - -| Column | Type | Integrity | -|--------|---------|-------------| -| id | integer | Primary key | -| name | varchar |   | - -**Pokemons** - -| Column | Type | Integrity | -|---------|---------|-------------| -| id | integer | Primary key | -| name | varchar |   | -| id_type | integer | Type(id) | - -with 1:N relationship between *Types* and *Pokémons* - -Examples are given for H2, Oracle, or MySQL databases (note that MySQL is currently not supported for GraalVM native image) - -To switch between JDBC drivers: - -- Uncomment the appropriate dependency in `pom.xml` -- Uncomment the configuration section in `application.yaml` and comment out the current one - -## Build - -To build a jar file -``` -mvn package -``` - -To build a native image (supported only with Oracle, MongoDB, or H2 databases) -``` -mvn package -Pnative-image -``` - -## Database -This example can run with any JDBC supported database. -In the `pom.xml` and `application.yaml` we provide configuration needed for Oracle database, MySQL and H2 database. -Start your database before running this example. - -Example docker commands to start databases in temporary containers: - -Oracle: -``` -docker run --rm --name xe -p 1521:1521 -p 8888:8080 wnameless/oracle-xe-11g-r2 -``` -For details on an Oracle Docker image, see https://github.com/oracle/docker-images/tree/master/OracleDatabase/SingleInstance - -H2: -``` -docker run --rm --name h2 -p 9092:9082 -p 8082:8082 nemerosa/h2 -``` -For details, see http://www.h2database.com/html/cheatSheet.html - -MySQL: -``` -docker run --rm --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root \ - -e MYSQL_DATABASE=pokemon -e MYSQL_USER=user -e MYSQL_PASSWORD=changeit mysql:5.7 -``` - - -## Run - -Then run the `io.helidon.examples.dbclient.pokemons.Main` class: -``` -java -jar target/helidon-examples-dbclient-pokemons.jar -``` - -Or run the native image: -``` -./target/helidon-examples-dbclient-pokemons -``` - -### Run with MongoDB - -It's possible to run example with MongoDB database. Start it using docker: -``` -docker run --rm --name mongo -p 27017:27017 mongo -``` - -Then run the `io.helidon.examples.dbclient.pokemons.Main` class with `mongo` argument: -``` -java -jar target/helidon-examples-dbclient-pokemons.jar mongo -``` - -## Test Example - -The application has the following endpoints: - -- http://localhost:8080/db - the main business endpoint (see `curl` commands below) -- http://localhost:8080/metrics - the metrics endpoint (query adds application metrics) -- http://localhost:8080/health - has a custom database health check - -Application also connects to zipkin on default address. -The query operation adds database trace. - -``` -# List all Pokémon -curl http://localhost:8080/db/pokemon - -# List all Pokémon types -curl http://localhost:8080/db/type - -# Get a single Pokémon by id -curl http://localhost:8080/db/pokemon/2 - -# Get a single Pokémon by name -curl http://localhost:8080/db/pokemon/name/Squirtle - -# Add a new Pokémon Rattata -curl -i -X POST -H 'Content-type: application/json' -d '{"id":7,"name":"Rattata","idType":1}' http://localhost:8080/db/pokemon - -# Rename Pokémon with id 7 to Raticate -curl -i -X PUT -H 'Content-type: application/json' -d '{"id":7,"name":"Raticate","idType":2}' http://localhost:8080/db/pokemon - -# Delete Pokémon with id 7 -curl -i -X DELETE http://localhost:8080/db/pokemon/7 -``` - -### Proxy - -Make sure that `localhost` is not being accessed trough proxy when proxy is configured on your system: -``` -export NO_PROXY='localhost' -``` - ---- - -Pokémon, and Pokémon character names are trademarks of Nintendo. diff --git a/examples/dbclient/pokemons/pom.xml b/examples/dbclient/pokemons/pom.xml deleted file mode 100644 index cd551b2fa1a..00000000000 --- a/examples/dbclient/pokemons/pom.xml +++ /dev/null @@ -1,209 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - - helidon-examples-dbclient-pokemons - Helidon Examples DB Client: Pokemons Database - - - io.helidon.examples.dbclient.pokemons.Main - - - - - io.helidon.tracing - helidon-tracing - - - io.helidon.tracing.providers - helidon-tracing-providers-zipkin - - - io.helidon.dbclient - helidon-dbclient-jdbc - - - io.helidon.dbclient - helidon-dbclient-mongodb - - - io.helidon.dbclient - helidon-dbclient-tracing - - - io.helidon.dbclient - helidon-dbclient-metrics - - - io.helidon.dbclient - helidon-dbclient-metrics-hikari - - - io.helidon.dbclient - helidon-dbclient-health - - - io.helidon.dbclient - helidon-dbclient-jsonp - - - io.helidon.integrations.db - ojdbc - - - io.helidon.integrations.db - h2 - - - org.slf4j - slf4j-jdk14 - - - io.helidon.config - helidon-config-yaml - - - io.helidon.webserver.observe - helidon-webserver-observe-metrics - runtime - - - io.helidon.metrics - helidon-metrics-system-meters - runtime - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver.observe - helidon-webserver-observe - - - io.helidon.webserver.observe - helidon-webserver-observe-health - - - io.helidon.health - helidon-health-checks - - - io.helidon.http.media - helidon-http-media-jsonp - - - io.helidon.http.media - helidon-http-media-jsonb - - - org.mongodb - mongodb-driver-sync - - - io.helidon.logging - helidon-logging-jul - runtime - - - org.testcontainers - junit-jupiter - test - - - org.testcontainers - mongodb - test - - - org.testcontainers - mysql - test - - - org.testcontainers - oracle-xe - test - - - io.helidon.webclient - helidon-webclient - test - - - com.mysql - mysql-connector-j - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.apache.maven.plugins - maven-failsafe-plugin - - - - integration-test - verify - - - - false - - - - - - - - diff --git a/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/Main.java b/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/Main.java deleted file mode 100644 index ce59813e9f5..00000000000 --- a/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/Main.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.dbclient.pokemons; - -import io.helidon.common.context.Contexts; -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.health.DbClientHealthCheck; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.http.HttpRouting; -import io.helidon.webserver.observe.ObserveFeature; -import io.helidon.webserver.observe.health.HealthObserver; - -/** - * Simple Hello World rest application. - */ -public final class Main { - - /** - * MongoDB configuration. Default configuration file {@code application.yaml} contains JDBC configuration. - */ - private static final String MONGO_CFG = "mongo.yaml"; - - /** - * Whether MongoDB support is selected. - */ - private static boolean mongo; - - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * - * @param args Command line arguments. Run with MongoDB support when 1st argument is mongo, run with JDBC support otherwise. - */ - public static void main(final String[] args) { - if (args != null && args.length > 0 && args[0] != null && "mongo".equalsIgnoreCase(args[0])) { - System.out.println("MongoDB database selected"); - mongo = true; - } else { - System.out.println("JDBC database selected"); - mongo = false; - } - startServer(); - } - - private static void startServer() { - - // load logging configuration - LogConfig.configureRuntime(); - - // By default, this will pick up application.yaml from the classpath - Config config = mongo ? Config.create(ConfigSources.classpath(MONGO_CFG)) : Config.create(); - Config.global(config); - - WebServer server = setupServer(WebServer.builder()); - - System.out.println("WEB server is up! http://localhost:" + server.port() + "/"); - } - - static WebServer setupServer(WebServerConfig.Builder builder) { - - Config config = Config.global(); - // Client services are added through a service loader - see mongoDB example for explicit services - DbClient dbClient = DbClient.create(config.get("db")); - Contexts.globalContext().register(dbClient); - - ObserveFeature observe = ObserveFeature.builder() - .config(config.get("server.features.observe")) - .addObserver(HealthObserver.builder() - .addCheck(DbClientHealthCheck.create(dbClient, config.get("db.health-check"))) - .build()) - .build(); - return builder.config(config.get("server")) - .addFeature(observe) - .routing(Main::routing) - .build() - .start(); - } - - /** - * Updates HTTP Routing. - */ - static void routing(HttpRouting.Builder routing) { - routing.register("/db", new PokemonService()); - } -} diff --git a/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/Pokemon.java b/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/Pokemon.java deleted file mode 100644 index 24dd312bc66..00000000000 --- a/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/Pokemon.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.dbclient.pokemons; - -/** - * POJO representing Pokémon. - * - * @param id id of the beast - * @param name name of the beast - * @param idType id of the beast type - */ -public record Pokemon(int id, String name, int idType) { -} diff --git a/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/PokemonMapper.java b/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/PokemonMapper.java deleted file mode 100644 index e52dd8e9801..00000000000 --- a/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/PokemonMapper.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.dbclient.pokemons; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import io.helidon.dbclient.DbColumn; -import io.helidon.dbclient.DbMapper; -import io.helidon.dbclient.DbRow; - -/** - * Maps database statements to {@link io.helidon.examples.dbclient.pokemons.Pokemon} class. - */ -public class PokemonMapper implements DbMapper { - - @Override - public Pokemon read(DbRow row) { - DbColumn id = row.column("id"); - DbColumn name = row.column("name"); - DbColumn type = row.column("idType"); - return new Pokemon(id.get(Integer.class), name.get(String.class), type.get(Integer.class)); - } - - @Override - public Map toNamedParameters(Pokemon value) { - Map map = new HashMap<>(3); - map.put("id", value.id()); - map.put("name", value.name()); - map.put("idType", value.idType()); - return map; - } - - @Override - public List toIndexedParameters(Pokemon value) { - List list = new ArrayList<>(3); - list.add(value.id()); - list.add(value.name()); - list.add(value.idType()); - return list; - } -} diff --git a/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/PokemonMapperProvider.java b/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/PokemonMapperProvider.java deleted file mode 100644 index 700aa3f8659..00000000000 --- a/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/PokemonMapperProvider.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.dbclient.pokemons; - -import java.util.Optional; - -import io.helidon.common.Weight; -import io.helidon.dbclient.DbMapper; -import io.helidon.dbclient.spi.DbMapperProvider; - -/** - * Provides pokemon mappers. - */ -@Weight(100) -public class PokemonMapperProvider implements DbMapperProvider { - private static final PokemonMapper MAPPER = new PokemonMapper(); - - @SuppressWarnings("unchecked") - @Override - public Optional> mapper(Class type) { - if (type.equals(Pokemon.class)) { - return Optional.of((DbMapper) MAPPER); - } - return Optional.empty(); - } -} diff --git a/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/PokemonService.java b/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/PokemonService.java deleted file mode 100644 index 7454b1eafc1..00000000000 --- a/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/PokemonService.java +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Copyright (c) 2019, 2024 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.dbclient.pokemons; - -import java.lang.System.Logger; -import java.lang.System.Logger.Level; -import java.util.Map; - -import io.helidon.common.context.Contexts; -import io.helidon.common.media.type.MediaTypes; -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbExecute; -import io.helidon.dbclient.DbTransaction; -import io.helidon.http.BadRequestException; -import io.helidon.http.NotFoundException; -import io.helidon.http.Status; -import io.helidon.webserver.http.Handler; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -import jakarta.json.Json; -import jakarta.json.JsonArray; -import jakarta.json.JsonArrayBuilder; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import jakarta.json.JsonReader; -import jakarta.json.JsonValue; - -/** - * An {@link HttpService} that uses {@link DbClient}. - */ -public class PokemonService implements HttpService { - - private static final Logger LOGGER = System.getLogger(PokemonService.class.getName()); - private static final JsonBuilderFactory JSON_FACTORY = Json.createBuilderFactory(Map.of()); - - private final DbClient dbClient; - private final boolean initSchema; - private final boolean initData; - - /** - * Create a new Pokémon service with a DB client. - */ - PokemonService() { - Config config = Config.global().get("db"); - this.dbClient = Contexts.globalContext() - .get(DbClient.class) - .orElseGet(() -> DbClient.create(config)); - - initSchema = config.get("init-schema").asBoolean().orElse(true); - initData = config.get("init-data").asBoolean().orElse(true); - init(); - } - - private void init() { - if (initSchema) { - initSchema(); - } - if (initData) { - initData(); - } - } - - private void initSchema() { - DbExecute exec = dbClient.execute(); - try { - exec.namedDml("create-types"); - exec.namedDml("create-pokemons"); - } catch (Exception ex1) { - LOGGER.log(Level.WARNING, "Could not create tables", ex1); - try { - deleteData(); - } catch (Exception ex2) { - LOGGER.log(Level.WARNING, "Could not delete tables", ex2); - } - } - } - - private void initData() { - DbTransaction tx = dbClient.transaction(); - try { - initTypes(tx); - initPokemons(tx); - tx.commit(); - } catch (Throwable t) { - tx.rollback(); - throw t; - } - } - - private static void initTypes(DbExecute exec) { - try (JsonReader reader = Json.createReader(PokemonService.class.getResourceAsStream("/pokemon-types.json"))) { - JsonArray types = reader.readArray(); - for (JsonValue typeValue : types) { - JsonObject type = typeValue.asJsonObject(); - exec.namedInsert("insert-type", - type.getInt("id"), - type.getString("name")); - } - } - } - - private static void initPokemons(DbExecute exec) { - try (JsonReader reader = Json.createReader(PokemonService.class.getResourceAsStream("/pokemons.json"))) { - JsonArray pokemons = reader.readArray(); - for (JsonValue pokemonValue : pokemons) { - JsonObject pokemon = pokemonValue.asJsonObject(); - exec.namedInsert("insert-pokemon", - pokemon.getInt("id"), - pokemon.getString("name"), - pokemon.getInt("idType")); - } - } - } - - private void deleteData() { - DbTransaction tx = dbClient.transaction(); - try { - tx.namedDelete("delete-all-pokemons"); - tx.namedDelete("delete-all-types"); - tx.commit(); - } catch (Throwable t) { - tx.rollback(); - throw t; - } - } - - @Override - public void routing(HttpRules rules) { - rules.get("/", this::index) - // List all types - .get("/type", this::listTypes) - // List all Pokémon - .get("/pokemon", this::listPokemons) - // Get Pokémon by name - .get("/pokemon/name/{name}", this::getPokemonByName) - // Get Pokémon by ID - .get("/pokemon/{id}", this::getPokemonById) - // Create new Pokémon - .post("/pokemon", Handler.create(Pokemon.class, this::insertPokemon)) - // Update name of existing Pokémon - .put("/pokemon", Handler.create(Pokemon.class, this::updatePokemon)) - // Delete Pokémon by ID including type relation - .delete("/pokemon/{id}", this::deletePokemonById); - } - - /** - * Return index page. - * - * @param request the server request - * @param response the server response - */ - private void index(ServerRequest request, ServerResponse response) { - response.headers().contentType(MediaTypes.TEXT_PLAIN); - response.send(""" - Pokemon JDBC Example: - GET /type - List all pokemon types - GET /pokemon - List all pokemons - GET /pokemon/{id} - Get pokemon by id - GET /pokemon/name/{name} - Get pokemon by name - POST /pokemon - Insert new pokemon: - {"id":,"name":,"type":} - PUT /pokemon - Update pokemon - {"id":,"name":,"type":} - DELETE /pokemon/{id} - Delete pokemon with specified id - """); - } - - /** - * Return JsonArray with all stored Pokémon. - * Pokémon object contains list of all type names. - * This method is abstract because implementation is DB dependent. - * - * @param request the server request - * @param response the server response - */ - private void listTypes(ServerRequest request, ServerResponse response) { - JsonArray jsonArray = dbClient.execute() - .namedQuery("select-all-types") - .map(row -> row.as(JsonObject.class)) - .collect(JSON_FACTORY::createArrayBuilder, JsonArrayBuilder::add, JsonArrayBuilder::addAll) - .build(); - response.send(jsonArray); - } - - /** - * Return JsonArray with all stored Pokémon. - * Pokémon object contains list of all type names. - * This method is abstract because implementation is DB dependent. - * - * @param request the server request - * @param response the server response - */ - private void listPokemons(ServerRequest request, ServerResponse response) { - JsonArray jsonArray = dbClient.execute().namedQuery("select-all-pokemons") - .map(row -> row.as(JsonObject.class)) - .collect(JSON_FACTORY::createArrayBuilder, JsonArrayBuilder::add, JsonArrayBuilder::addAll) - .build(); - response.send(jsonArray); - } - - /** - * Get a single Pokémon by id. - * - * @param request server request - * @param response server response - */ - private void getPokemonById(ServerRequest request, ServerResponse response) { - int pokemonId = Integer.parseInt(request.path() - .pathParameters() - .get("id")); - - response.send(dbClient.execute().createNamedGet("select-pokemon-by-id") - .addParam("id", pokemonId) - .execute() - .orElseThrow(() -> new NotFoundException("Pokemon " + pokemonId + " not found")) - .as(JsonObject.class)); - } - - /** - * Get a single Pokémon by name. - * - * @param request server request - * @param response server response - */ - private void getPokemonByName(ServerRequest request, ServerResponse response) { - String pokemonName = request.path().pathParameters().get("name"); - response.send(dbClient.execute().namedGet("select-pokemon-by-name", pokemonName) - .orElseThrow(() -> new NotFoundException("Pokemon " + pokemonName + " not found")) - .as(JsonObject.class)); - } - - /** - * Insert new Pokémon with specified name. - * - * @param pokemon request entity - * @param response the server response - */ - private void insertPokemon(Pokemon pokemon, ServerResponse response) { - long count = dbClient.execute().createNamedInsert("insert-pokemon") - .indexedParam(pokemon) - .execute(); - response.status(Status.CREATED_201) - .send("Inserted: " + count + " values\n"); - } - - /** - * Update a Pokémon. - * Uses a transaction. - * - * @param pokemon request entity - * @param response the server response - */ - private void updatePokemon(Pokemon pokemon, ServerResponse response) { - long count = dbClient.execute().createNamedUpdate("update-pokemon-by-id") - .namedParam(pokemon) - .execute(); - response.send("Updated: " + count + " values\n"); - } - - /** - * Delete Pokémon with specified id (key). - * - * @param request the server request - * @param response the server response - */ - private void deletePokemonById(ServerRequest request, ServerResponse response) { - int id = request.path() - .pathParameters() - .first("id").map(Integer::parseInt) - .orElseThrow(() -> new BadRequestException("No pokemon id")); - dbClient.execute().createNamedDelete("delete-pokemon-by-id") - .addParam("id", id) - .execute(); - response.status(Status.NO_CONTENT_204) - .send(); - } -} diff --git a/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/package-info.java b/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/package-info.java deleted file mode 100644 index 4ddeaee4d58..00000000000 --- a/examples/dbclient/pokemons/src/main/java/io/helidon/examples/dbclient/pokemons/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2019, 2021 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. - */ - -/** - * Quick start demo application. - */ -package io.helidon.examples.dbclient.pokemons; diff --git a/examples/dbclient/pokemons/src/main/resources/META-INF/services/io.helidon.dbclient.spi.DbMapperProvider b/examples/dbclient/pokemons/src/main/resources/META-INF/services/io.helidon.dbclient.spi.DbMapperProvider deleted file mode 100644 index 1d19c17ca87..00000000000 --- a/examples/dbclient/pokemons/src/main/resources/META-INF/services/io.helidon.dbclient.spi.DbMapperProvider +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2019, 2021 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. -# - -io.helidon.examples.dbclient.pokemons.PokemonMapperProvider diff --git a/examples/dbclient/pokemons/src/main/resources/application.yaml b/examples/dbclient/pokemons/src/main/resources/application.yaml deleted file mode 100644 index ff61f588aa9..00000000000 --- a/examples/dbclient/pokemons/src/main/resources/application.yaml +++ /dev/null @@ -1,79 +0,0 @@ -# -# Copyright (c) 2019, 2023 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 - -tracing: - service: jdbc-db - -# see README.md for details how to run databases in docker -db: - source: jdbc - connection: - # - # Oracle configuration - # - url: "jdbc:oracle:thin:@localhost:1521/XE" - username: "system" - password: "oracle" - # - # MySQL configuration - # -# url: jdbc:mysql://127.0.0.1:3306/pokemon?useSSL=false -# username: user -# password: password -# poolName: "mysql" - # - # H2 configuration - # -# url: "jdbc:h2:tcp://localhost:9092/~test" -# username: h2 -# password: "${EMPTY}" -# poolName: h2 - initializationFailTimeout: -1 - connectionTimeout: 2000 - helidon: - pool-metrics: - enabled: true - # name prefix defaults to "db.pool." - if you have more than one client within a JVM, you may want to distinguish between them - name-prefix: "hikari." - services: - tracing: - - enabled: true - metrics: - - type: TIMER - health-check: - type: "query" - statementName: "health-check" - statements: - # Health check query statement for MySQL and H2 databases -# health-check: "SELECT 0" - # Health check query statement for Oracle database - health-check: "SELECT 1 FROM DUAL" - create-types: "CREATE TABLE PokeTypes (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(64) NOT NULL)" - create-pokemons: "CREATE TABLE Pokemons (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(64) NOT NULL, id_type INTEGER NOT NULL REFERENCES PokeTypes(id))" - select-all-types: "SELECT id, name FROM PokeTypes" - select-all-pokemons: "SELECT id, name, id_type FROM Pokemons" - select-pokemon-by-id: "SELECT id, name, id_type FROM Pokemons WHERE id = :id" - select-pokemon-by-name: "SELECT id, name, id_type FROM Pokemons WHERE name = ?" - insert-type: "INSERT INTO PokeTypes(id, name) VALUES(?, ?)" - insert-pokemon: "INSERT INTO Pokemons(id, name, id_type) VALUES(?, ?, ?)" - update-pokemon-by-id: "UPDATE Pokemons SET name = :name, id_type = :idType WHERE id = :id" - delete-pokemon-by-id: "DELETE FROM Pokemons WHERE id = :id" - delete-all-types: "DELETE FROM PokeTypes" - delete-all-pokemons: "DELETE FROM Pokemons" diff --git a/examples/dbclient/pokemons/src/main/resources/logging.properties b/examples/dbclient/pokemons/src/main/resources/logging.properties deleted file mode 100644 index 550b8d9a48c..00000000000 --- a/examples/dbclient/pokemons/src/main/resources/logging.properties +++ /dev/null @@ -1,35 +0,0 @@ -# -# Copyright (c) 2019, 2024 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.HelidonConsoleHandler - -# Global default logging level. Can be overridden by specific handlers and loggers -.level=INFO - -# Helidon Web Server has a custom log formatter that extends SimpleFormatter. -# It replaces "!thread!" with the current thread name -io.helidon.logging.jul.HelidonConsoleHandler.level=ALL -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 - -#Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.common.level=INFO diff --git a/examples/dbclient/pokemons/src/main/resources/mongo.yaml b/examples/dbclient/pokemons/src/main/resources/mongo.yaml deleted file mode 100644 index 5e46bf7d340..00000000000 --- a/examples/dbclient/pokemons/src/main/resources/mongo.yaml +++ /dev/null @@ -1,115 +0,0 @@ -# -# Copyright (c) 2019, 2023 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 - -tracing: - service: mongo-db - -db: - source: "mongoDb" - connection: - url: "mongodb://127.0.0.1:27017/pokemon" - init-schema: false - # Transactions are not supported - init-data: false - services: - tracing: - - enabled: true - health-check: - type: "query" - statementName: "health-check" - statements: - # Health check statement. HealthCheck statement type must be a query. - health-check: '{ - "operation": "command", - "query": { ping: 1 } - }' - ## Create database schema - # Select all types - select-all-types: '{ - "collection": "types", - "operation": "query", - "projection": { id: 1, name: 1, _id: 0 }, - "query": {} - }' - # Select all pokemons without type information - select-all-pokemons: '{ - "collection": "pokemons", - "operation": "query", - "projection": { id: 1, name: 1, id_type: 1, _id: 0 }, - "query": {} - }' - # Select pokemon by id - select-pokemon-by-id: '{ - "collection": "pokemons", - "operation": "query", - "projection": { id: 1, name: 1, id_type: 1, _id: 0 }, - "query": { id: $id } - }' - # Select pokemon by name - select-pokemon-by-name: '{ - "collection": "pokemons", - "operation": "query", - "projection": { id: 1, name: 1, id_type: 1, _id: 0 }, - "query": { name: ? } - }' - # Insert records into database - insert-type: '{ - "collection": "types", - "operation": "insert", - "value": { - "id": ?, - "name": ? - } - }' - insert-pokemon: '{ - "collection": "pokemons", - "operation": "insert", - "value": { - "id": ?, - "name": ?, - "id_type": ? - } - }' - # Update name of pokemon specified by id - update-pokemon-by-id: '{ - "collection": "pokemons", - "operation": "update", - "value":{ $set: { "name": $name, "id_type": $idType } }, - "query": { id: $id } - }' - # Delete pokemon by id - delete-pokemon-by-id: '{ - "collection": "pokemons", - "operation": "delete", - "query": { id: $id } - }' - # Delete all types - delete-all-types: '{ - "collection": "types", - "operation": "delete", - "query": { } - }' - # Delete all pokemons - delete-all-pokemons: '{ - "collection": "pokemons", - "operation": "delete", - "query": { } - }' - diff --git a/examples/dbclient/pokemons/src/main/resources/pokemon-types.json b/examples/dbclient/pokemons/src/main/resources/pokemon-types.json deleted file mode 100644 index 646ec725b82..00000000000 --- a/examples/dbclient/pokemons/src/main/resources/pokemon-types.json +++ /dev/null @@ -1,20 +0,0 @@ -[ - {"id": 1, "name": "Normal"}, - {"id": 2, "name": "Fighting"}, - {"id": 3, "name": "Flying"}, - {"id": 4, "name": "Poison"}, - {"id": 5, "name": "Ground"}, - {"id": 6, "name": "Rock"}, - {"id": 7, "name": "Bug"}, - {"id": 8, "name": "Ghost"}, - {"id": 9, "name": "Steel"}, - {"id": 10, "name": "Fire"}, - {"id": 11, "name": "Water"}, - {"id": 12, "name": "Grass"}, - {"id": 13, "name": "Electric"}, - {"id": 14, "name": "Psychic"}, - {"id": 15, "name": "Ice"}, - {"id": 16, "name": "Dragon"}, - {"id": 17, "name": "Dark"}, - {"id": 18, "name": "Fairy"} -] diff --git a/examples/dbclient/pokemons/src/main/resources/pokemons.json b/examples/dbclient/pokemons/src/main/resources/pokemons.json deleted file mode 100644 index c4e78bed732..00000000000 --- a/examples/dbclient/pokemons/src/main/resources/pokemons.json +++ /dev/null @@ -1,8 +0,0 @@ -[ - {"id": 1, "name": "Bulbasaur", "idType": 12}, - {"id": 2, "name": "Charmander", "idType": 10}, - {"id": 3, "name": "Squirtle", "idType": 11}, - {"id": 4, "name": "Caterpie", "idType": 7}, - {"id": 5, "name": "Weedle", "idType": 7}, - {"id": 6, "name": "Pidgey", "idType": 3} -] diff --git a/examples/dbclient/pokemons/src/test/java/io/helidon/examples/dbclient/pokemons/AbstractPokemonServiceTest.java b/examples/dbclient/pokemons/src/test/java/io/helidon/examples/dbclient/pokemons/AbstractPokemonServiceTest.java deleted file mode 100644 index 6f51f44de63..00000000000 --- a/examples/dbclient/pokemons/src/test/java/io/helidon/examples/dbclient/pokemons/AbstractPokemonServiceTest.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2023, 2024 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.dbclient.pokemons; - -import java.util.List; -import java.util.Map; - -import io.helidon.http.Status; -import io.helidon.http.media.jsonp.JsonpSupport; -import io.helidon.webclient.api.ClientResponseTyped; -import io.helidon.webclient.api.WebClient; -import io.helidon.webserver.WebServer; - -import jakarta.json.Json; -import jakarta.json.JsonArray; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import jakarta.json.JsonReader; -import jakarta.json.JsonValue; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - -abstract class AbstractPokemonServiceTest { - private static final JsonBuilderFactory JSON_FACTORY = Json.createBuilderFactory(Map.of()); - - private static WebServer server; - private static WebClient client; - - static void beforeAll() { - server = Main.setupServer(WebServer.builder()); - client = WebClient.create(config -> config.baseUri("http://localhost:" + server.port()) - .addMediaSupport(JsonpSupport.create())); - } - - static void afterAll() { - if (server != null && server.isRunning()) { - server.stop(); - } - } - - @Test - void testListAllPokemons() { - ClientResponseTyped response = client.get("/db/pokemon").request(JsonArray.class); - assertThat(response.status(), is(Status.OK_200)); - List names = response.entity().stream().map(AbstractPokemonServiceTest::mapName).toList(); - assertThat(names, is(pokemonNames())); - } - - @Test - void testListAllPokemonTypes() { - ClientResponseTyped response = client.get("/db/type").request(JsonArray.class); - assertThat(response.status(), is(Status.OK_200)); - List names = response.entity().stream().map(AbstractPokemonServiceTest::mapName).toList(); - assertThat(names, is(pokemonTypes())); - } - - @Test - void testGetPokemonById() { - ClientResponseTyped response = client.get("/db/pokemon/2").request(JsonObject.class); - assertThat(response.status(), is(Status.OK_200)); - assertThat(name(response.entity()), is("Charmander")); - } - - @Test - void testGetPokemonByName() { - ClientResponseTyped response = client.get("/db/pokemon/name/Squirtle").request(JsonObject.class); - assertThat(response.status(), is(Status.OK_200)); - assertThat(id(response.entity()), is(3)); - } - - @Test - void testAddUpdateDeletePokemon() { - JsonObject pokemon; - ClientResponseTyped response; - - // add a new Pokémon Rattata - pokemon = JSON_FACTORY.createObjectBuilder() - .add("id", 7) - .add("name", "Rattata") - .add("idType", 1) - .build(); - response = client.post("/db/pokemon").submit(pokemon, String.class); - assertThat(response.status(), is(Status.CREATED_201)); - - // rename Pokémon with id 7 to Raticate - pokemon = JSON_FACTORY.createObjectBuilder() - .add("id", 7) - .add("name", "Raticate") - .add("idType", 2) - .build(); - - response = client.put("/db/pokemon").submit(pokemon, String.class); - assertThat(response.status(), is(Status.OK_200)); - - // delete Pokémon with id 7 - response = client.delete("/db/pokemon/7").request(String.class); - assertThat(response.status(), is(Status.NO_CONTENT_204)); - - response = client.get("/db/pokemon/7").request(String.class); - assertThat(response.status(), is(Status.NOT_FOUND_404)); - } - - private static List pokemonNames() { - try (JsonReader reader = Json.createReader(PokemonService.class.getResourceAsStream("/pokemons.json"))) { - return reader.readArray().stream().map(AbstractPokemonServiceTest::mapName).toList(); - } - } - - private static List pokemonTypes() { - try (JsonReader reader = Json.createReader(PokemonService.class.getResourceAsStream("/pokemon-types.json"))) { - return reader.readArray().stream().map(AbstractPokemonServiceTest::mapName).toList(); - } - } - - private static String mapName(JsonValue value) { - return name(value.asJsonObject()); - } - - private static String name(JsonObject json) { - return json.containsKey("name") - ? json.getString("name") - : json.getString("NAME"); - } - - private static int id(JsonObject json) { - return json.containsKey("id") - ? json.getInt("id") - : json.getInt("ID"); - } - -} diff --git a/examples/dbclient/pokemons/src/test/java/io/helidon/examples/dbclient/pokemons/PokemonServiceH2IT.java b/examples/dbclient/pokemons/src/test/java/io/helidon/examples/dbclient/pokemons/PokemonServiceH2IT.java deleted file mode 100644 index 25774f1744f..00000000000 --- a/examples/dbclient/pokemons/src/test/java/io/helidon/examples/dbclient/pokemons/PokemonServiceH2IT.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2023, 2024 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.dbclient.pokemons; - -import java.util.Map; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.testcontainers.containers.GenericContainer; -import org.testcontainers.containers.wait.strategy.Wait; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; -import org.testcontainers.utility.DockerImageName; - -import static io.helidon.config.ConfigSources.classpath; - -/** - * Tests {@link io.helidon.examples.dbclient.pokemons.PokemonService}. - */ -@Testcontainers(disabledWithoutDocker = true) -class PokemonServiceH2IT extends AbstractPokemonServiceTest { - private static final DockerImageName H2_IMAGE = DockerImageName.parse("nemerosa/h2"); - - @Container - static GenericContainer container = new GenericContainer<>(H2_IMAGE) - .withExposedPorts(9082) - .waitingFor(Wait.forLogMessage("(.*)Web Console server running at(.*)", 1)); - - @BeforeAll - static void start() { - String url = String.format("jdbc:h2:tcp://localhost:%s/~./test", container.getMappedPort(9082)); - Config.global(Config.builder() - .addSource(ConfigSources.create(Map.of("db.connection.url", url))) - .addSource(classpath("application-h2-test.yaml")) - .build()); - beforeAll(); - } - - @AfterAll - static void stop() { - afterAll(); - } -} diff --git a/examples/dbclient/pokemons/src/test/java/io/helidon/examples/dbclient/pokemons/PokemonServiceMongoIT.java b/examples/dbclient/pokemons/src/test/java/io/helidon/examples/dbclient/pokemons/PokemonServiceMongoIT.java deleted file mode 100644 index d0013d5657e..00000000000 --- a/examples/dbclient/pokemons/src/test/java/io/helidon/examples/dbclient/pokemons/PokemonServiceMongoIT.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2024 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.dbclient.pokemons; - -import java.util.Map; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.testcontainers.containers.MongoDBContainer; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; - -import static io.helidon.config.ConfigSources.classpath; - -@Testcontainers(disabledWithoutDocker = true) -public class PokemonServiceMongoIT extends AbstractPokemonServiceTest { - - @Container - static final MongoDBContainer container = new MongoDBContainer("mongo") - .withExposedPorts(27017); - - @BeforeAll - static void start() { - String url = String.format("mongodb://127.0.0.1:%s/pokemon", container.getMappedPort(27017)); - Config.global(Config.builder() - .addSource(ConfigSources.create(Map.of("db.connection.url", url))) - .addSource(classpath("application-mongo-test.yaml")) - .build()); - beforeAll(); - } - - @AfterAll - static void stop() { - afterAll(); - } - - void testListAllPokemons() { - //Skip this test - Transactions are not supported - } - - void testListAllPokemonTypes() { - //Skip this test - Transactions are not supported - } - - void testGetPokemonById() { - //Skip this test - Transactions are not supported - } - - void testGetPokemonByName() { - //Skip this test - Transactions are not supported - } - -} diff --git a/examples/dbclient/pokemons/src/test/java/io/helidon/examples/dbclient/pokemons/PokemonServiceMySQLIT.java b/examples/dbclient/pokemons/src/test/java/io/helidon/examples/dbclient/pokemons/PokemonServiceMySQLIT.java deleted file mode 100644 index 36d03ddc02e..00000000000 --- a/examples/dbclient/pokemons/src/test/java/io/helidon/examples/dbclient/pokemons/PokemonServiceMySQLIT.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2023, 2024 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.dbclient.pokemons; - -import java.util.Map; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.testcontainers.containers.MySQLContainer; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; - -import static io.helidon.config.ConfigSources.classpath; - -@Testcontainers(disabledWithoutDocker = true) -public class PokemonServiceMySQLIT extends AbstractPokemonServiceTest { - - @Container - static MySQLContainer container = new MySQLContainer<>("mysql:8.0.36") - .withUsername("user") - .withPassword("changeit") - .withNetworkAliases("mysql") - .withDatabaseName("pokemon"); - - @BeforeAll - static void start() { - Config.global(Config.builder() - .addSource(ConfigSources.create(Map.of("db.connection.url", container.getJdbcUrl()))) - .addSource(classpath("application-mysql-test.yaml")) - .build()); - beforeAll(); - } - - @AfterAll - static void stop() { - afterAll(); - } - -} diff --git a/examples/dbclient/pokemons/src/test/java/io/helidon/examples/dbclient/pokemons/PokemonServiceOracleIT.java b/examples/dbclient/pokemons/src/test/java/io/helidon/examples/dbclient/pokemons/PokemonServiceOracleIT.java deleted file mode 100644 index cf2d4f6d916..00000000000 --- a/examples/dbclient/pokemons/src/test/java/io/helidon/examples/dbclient/pokemons/PokemonServiceOracleIT.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2024 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.dbclient.pokemons; - -import java.util.Map; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.testcontainers.containers.OracleContainer; -import org.testcontainers.containers.wait.strategy.Wait; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; -import org.testcontainers.utility.DockerImageName; - -import static io.helidon.config.ConfigSources.classpath; - -@Testcontainers(disabledWithoutDocker = true) -public class PokemonServiceOracleIT extends AbstractPokemonServiceTest { - - private static final DockerImageName image = DockerImageName.parse("wnameless/oracle-xe-11g-r2") - .asCompatibleSubstituteFor("gvenzl/oracle-xe"); - - @Container - static OracleContainer container = new OracleContainer(image) - .withExposedPorts(1521, 8080) - .withDatabaseName("XE") - .usingSid() - .waitingFor(Wait.forListeningPorts(1521, 8080)); - - @BeforeAll - static void setup() { - Config.global(Config.builder() - .addSource(ConfigSources.create(Map.of("db.connection.url", container.getJdbcUrl()))) - .addSource(classpath("application-oracle-test.yaml")) - .build()); - beforeAll(); - } - - @AfterAll - static void stop() { - afterAll(); - } -} diff --git a/examples/dbclient/pokemons/src/test/resources/application-h2-test.yaml b/examples/dbclient/pokemons/src/test/resources/application-h2-test.yaml deleted file mode 100644 index daccc3736a0..00000000000 --- a/examples/dbclient/pokemons/src/test/resources/application-h2-test.yaml +++ /dev/null @@ -1,59 +0,0 @@ -# -# Copyright (c) 2024 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 - -tracing: - service: jdbc-db - -# see README.md for details how to run databases in docker -db: - source: jdbc - connection: - username: sa - password: "${EMPTY}" - poolName: h2 - initializationFailTimeout: -1 - connectionTimeout: 2000 - helidon: - pool-metrics: - enabled: true - # name prefix defaults to "db.pool." - if you have more than one client within a JVM, you may want to distinguish between them - name-prefix: "hikari." - services: - tracing: - - enabled: true - metrics: - - type: TIMER - health-check: - type: "query" - statementName: "health-check" - statements: - health-check: "SELECT 0" - create-types: "CREATE TABLE PokeTypes (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(64) NOT NULL)" - create-pokemons: "CREATE TABLE Pokemons (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(64) NOT NULL, id_type INTEGER NOT NULL REFERENCES PokeTypes(id))" - select-all-types: "SELECT id, name FROM PokeTypes" - select-all-pokemons: "SELECT id, name, id_type FROM Pokemons" - select-pokemon-by-id: "SELECT id, name, id_type FROM Pokemons WHERE id = :id" - select-pokemon-by-name: "SELECT id, name, id_type FROM Pokemons WHERE name = ?" - insert-type: "INSERT INTO PokeTypes(id, name) VALUES(?, ?)" - insert-pokemon: "INSERT INTO Pokemons(id, name, id_type) VALUES(?, ?, ?)" - update-pokemon-by-id: "UPDATE Pokemons SET name = :name, id_type = :idType WHERE id = :id" - delete-pokemon-by-id: "DELETE FROM Pokemons WHERE id = :id" - delete-all-types: "DELETE FROM PokeTypes" - delete-all-pokemons: "DELETE FROM Pokemons" diff --git a/examples/dbclient/pokemons/src/test/resources/application-mongo-test.yaml b/examples/dbclient/pokemons/src/test/resources/application-mongo-test.yaml deleted file mode 100644 index aee39d5e40b..00000000000 --- a/examples/dbclient/pokemons/src/test/resources/application-mongo-test.yaml +++ /dev/null @@ -1,113 +0,0 @@ -# -# Copyright (c) 2024 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 - -tracing: - service: mongo-db - -db: - source: "mongoDb" - init-schema: false - # Transactions are not supported - init-data: false - services: - tracing: - - enabled: true - health-check: - type: "query" - statementName: "health-check" - statements: - # Health check statement. HealthCheck statement type must be a query. - health-check: '{ - "operation": "command", - "query": { ping: 1 } - }' - ## Create database schema - # Select all types - select-all-types: '{ - "collection": "types", - "operation": "query", - "projection": { id: 1, name: 1, _id: 0 }, - "query": {} - }' - # Select all pokemons without type information - select-all-pokemons: '{ - "collection": "pokemons", - "operation": "query", - "projection": { id: 1, name: 1, id_type: 1, _id: 0 }, - "query": {} - }' - # Select pokemon by id - select-pokemon-by-id: '{ - "collection": "pokemons", - "operation": "query", - "projection": { id: 1, name: 1, id_type: 1, _id: 0 }, - "query": { id: $id } - }' - # Select pokemon by name - select-pokemon-by-name: '{ - "collection": "pokemons", - "operation": "query", - "projection": { id: 1, name: 1, id_type: 1, _id: 0 }, - "query": { name: ? } - }' - # Insert records into database - insert-type: '{ - "collection": "types", - "operation": "insert", - "value": { - "id": ?, - "name": ? - } - }' - insert-pokemon: '{ - "collection": "pokemons", - "operation": "insert", - "value": { - "id": ?, - "name": ?, - "id_type": ? - } - }' - # Update name of pokemon specified by id - update-pokemon-by-id: '{ - "collection": "pokemons", - "operation": "update", - "value":{ $set: { "name": $name, "id_type": $idType } }, - "query": { id: $id } - }' - # Delete pokemon by id - delete-pokemon-by-id: '{ - "collection": "pokemons", - "operation": "delete", - "query": { id: $id } - }' - # Delete all types - delete-all-types: '{ - "collection": "types", - "operation": "delete", - "query": { } - }' - # Delete all pokemons - delete-all-pokemons: '{ - "collection": "pokemons", - "operation": "delete", - "query": { } - }' - diff --git a/examples/dbclient/pokemons/src/test/resources/application-mysql-test.yaml b/examples/dbclient/pokemons/src/test/resources/application-mysql-test.yaml deleted file mode 100644 index 58e56aee301..00000000000 --- a/examples/dbclient/pokemons/src/test/resources/application-mysql-test.yaml +++ /dev/null @@ -1,59 +0,0 @@ -# -# Copyright (c) 2024 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 - -tracing: - service: jdbc-db - -# see README.md for details how to run databases in docker -db: - source: jdbc - connection: - username: user - password: changeit - poolName: "mysql" - initializationFailTimeout: -1 - connectionTimeout: 2000 - helidon: - pool-metrics: - enabled: true - # name prefix defaults to "db.pool." - if you have more than one client within a JVM, you may want to distinguish between them - name-prefix: "hikari." - services: - tracing: - - enabled: true - metrics: - - type: TIMER - health-check: - type: "query" - statementName: "health-check" - statements: - health-check: "SELECT 0" - create-types: "CREATE TABLE PokeTypes (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(64) NOT NULL)" - create-pokemons: "CREATE TABLE Pokemons (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(64) NOT NULL, id_type INTEGER NOT NULL REFERENCES PokeTypes(id))" - select-all-types: "SELECT id, name FROM PokeTypes" - select-all-pokemons: "SELECT id, name, id_type FROM Pokemons" - select-pokemon-by-id: "SELECT id, name, id_type FROM Pokemons WHERE id = :id" - select-pokemon-by-name: "SELECT id, name, id_type FROM Pokemons WHERE name = ?" - insert-type: "INSERT INTO PokeTypes(id, name) VALUES(?, ?)" - insert-pokemon: "INSERT INTO Pokemons(id, name, id_type) VALUES(?, ?, ?)" - update-pokemon-by-id: "UPDATE Pokemons SET name = :name, id_type = :idType WHERE id = :id" - delete-pokemon-by-id: "DELETE FROM Pokemons WHERE id = :id" - delete-all-types: "DELETE FROM PokeTypes" - delete-all-pokemons: "DELETE FROM Pokemons" diff --git a/examples/dbclient/pokemons/src/test/resources/application-oracle-test.yaml b/examples/dbclient/pokemons/src/test/resources/application-oracle-test.yaml deleted file mode 100644 index 66d62ec06d2..00000000000 --- a/examples/dbclient/pokemons/src/test/resources/application-oracle-test.yaml +++ /dev/null @@ -1,58 +0,0 @@ -# -# Copyright (c) 2024 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 - -tracing: - service: jdbc-db - -# see README.md for details how to run databases in docker -db: - source: jdbc - connection: - username: "system" - password: "oracle" - initializationFailTimeout: -1 - connectionTimeout: 2000 - helidon: - pool-metrics: - enabled: true - # name prefix defaults to "db.pool." - if you have more than one client within a JVM, you may want to distinguish between them - name-prefix: "hikari." - services: - tracing: - - enabled: true - metrics: - - type: TIMER - health-check: - type: "query" - statementName: "health-check" - statements: - health-check: "SELECT 1 FROM DUAL" - create-types: "CREATE TABLE PokeTypes (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(64) NOT NULL)" - create-pokemons: "CREATE TABLE Pokemons (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(64) NOT NULL, id_type INTEGER NOT NULL REFERENCES PokeTypes(id))" - select-all-types: "SELECT id, name FROM PokeTypes" - select-all-pokemons: "SELECT id, name, id_type FROM Pokemons" - select-pokemon-by-id: "SELECT id, name, id_type FROM Pokemons WHERE id = :id" - select-pokemon-by-name: "SELECT id, name, id_type FROM Pokemons WHERE name = ?" - insert-type: "INSERT INTO PokeTypes(id, name) VALUES(?, ?)" - insert-pokemon: "INSERT INTO Pokemons(id, name, id_type) VALUES(?, ?, ?)" - update-pokemon-by-id: "UPDATE Pokemons SET name = :name, id_type = :idType WHERE id = :id" - delete-pokemon-by-id: "DELETE FROM Pokemons WHERE id = :id" - delete-all-types: "DELETE FROM PokeTypes" - delete-all-pokemons: "DELETE FROM Pokemons" diff --git a/examples/dbclient/pom.xml b/examples/dbclient/pom.xml deleted file mode 100644 index c6ba70766d3..00000000000 --- a/examples/dbclient/pom.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples - helidon-examples-project - 4.1.0-SNAPSHOT - - - pom - - io.helidon.examples.dbclient - helidon-examples-dbclient-project - Helidon Examples DB Client - - - Examples of Helidon DB Client - - - - - jdbc - mongodb - common - pokemons - - diff --git a/examples/employee-app/.dockerignore b/examples/employee-app/.dockerignore deleted file mode 100644 index c8b241f2215..00000000000 --- a/examples/employee-app/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -target/* \ No newline at end of file diff --git a/examples/employee-app/Dockerfile b/examples/employee-app/Dockerfile deleted file mode 100644 index fc8d642433c..00000000000 --- a/examples/employee-app/Dockerfile +++ /dev/null @@ -1,54 +0,0 @@ -# -# Copyright (c) 2019, 2024 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. -# - -# 1st stage, build the app -FROM container-registry.oracle.com/java/jdk-no-fee-term:21 as build - -# Install maven -WORKDIR /usr/share -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 -Dmaven.test.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 container-registry.oracle.com/java/jdk-no-fee-term:21 -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/helidon-examples-employee-app.jar ./ -COPY --from=build /helidon/target/libs ./libs - -CMD ["java", "-jar", "helidon-examples-employee-app.jar"] - -EXPOSE 8080 diff --git a/examples/employee-app/README.md b/examples/employee-app/README.md deleted file mode 100644 index e607a8b2fb9..00000000000 --- a/examples/employee-app/README.md +++ /dev/null @@ -1,293 +0,0 @@ -# Helidon Quickstart SE - Employee Directory Example - -This project implements an employee directory REST service using Helidon SE. - The application is composed of a Helidon REST Microservice backend along with - an HTML/JavaScript front end. The source for both application is included with - the Maven project. - -By default, the service uses a ArrayList backend with sample data. You can connect - the backend application to an Oracle database by changing the values in the - `resources/application.yaml` file. - -The service uses Helidon DB Client to access the database. - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-employee-app.jar -``` - -## Create script -If you do not have the employee table in your database, you can create it and required resources as follows: - -```sql -CREATE TABLE EMPLOYEE (ID NUMBER(6), - FIRSTNAME VARCHAR2(20), - LASTNAME VARCHAR2(25), - EMAIL VARCHAR2(30), - PHONE VARCHAR2(30), - BIRTHDATE VARCHAR2(15), - TITLE VARCHAR2(20), - DEPARTMENT VARCHAR2(20)); - -ALTER TABLE EMPLOYEE ADD (CONSTRAINT emp_id_pk PRIMARY KEY (ID)); - -CREATE SEQUENCE EMPLOYEE_SEQ INCREMENT BY 1 NOCACHE NOCYCLE; -``` - -## Exercise the application -Get all employees. -```sh -curl -X GET curl -X GET http://localhost:8080/employees -``` - -Only 1 output record is shown for brevity: -```json -[ - { - "birthDate": "1970-11-28T08:28:48.078Z", - "department": "Mobility", - "email": "Hugh.Jast@example.com", - "firstName": "Hugh", - "id": "48cf06ad-6ed4-47e6-ac44-3ea9c67cbe2d", - "lastName": "Jast", - "phone": "730-715-4446", - "title": "National Data Strategist" - } -] -``` - - -Get all employees whose last name contains "S". -```sh -curl -X GET http://localhost:8080/employees/lastname/S -``` - -Only 1 output record is shown for brevity: -```json -[ - { - "birthDate": "1978-03-18T17:00:12.938Z", - "department": "Security", - "email": "Zora.Sawayn@example.com", - "firstName": "Zora", - "id": "d7b583a2-f068-40d9-aec0-6f87899c5d8a", - "lastName": "Sawayn", - "phone": "923-814-0502", - "title": "Dynamic Marketing Designer" - } -] -``` - -Get an individual record. -```sh -curl -X GET http://localhost:8080/employees/48cf06ad-6ed4-47e6-ac44-3ea9c67cbe2d -``` -Output: -```json -[ - { - "birthDate": "1970-11-28T08:28:48.078Z", - "department": "Mobility", - "email": "Hugh.Jast@example.com", - "firstName": "Hugh", - "id": "48cf06ad-6ed4-47e6-ac44-3ea9c67cbe2d", - "lastName": "Jast", - "phone": "730-715-4446", - "title": "National Data Strategist" - } -] -``` - -Connect with a web browser at: -```txt -http://localhost:8080/public/index.html -``` - - -## Try health and metrics - -```sh -curl -s -X GET http://localhost:8080/health -``` - -```json -{ - "outcome": "UP", - "checks": [ - { - "name": "deadlock", - "state": "UP" - }, - { - "name": "diskSpace", - "state": "UP", - "data": { - "free": "306.61 GB", - "freeBytes": 329225338880, - "percentFree": "65.84%", - "total": "465.72 GB", - "totalBytes": 500068036608 - } - }, - { - "name": "heapMemory", - "state": "UP", - "data": { - "free": "239.35 MB", - "freeBytes": 250980656, - "max": "4.00 GB", - "maxBytes": 4294967296, - "percentFree": "99.59%", - "total": "256.00 MB", - "totalBytes": 268435456 - } - } - ] -} -``` - -### Prometheus Format - -```sh -curl -s -X GET http://localhost:8080/metrics -``` - -Only 1 output item is shown for brevity: -```txt -# TYPE base:classloader_current_loaded_class_count counter -# HELP base:classloader_current_loaded_class_count Displays the number of classes that are currently loaded in the Java virtual machine. -base:classloader_current_loaded_class_count 3995 -``` - -### JSON Format -```sh -curl -H 'Accept: application/json' -X GET http://localhost:8080/metrics -``` - -Output: -```json -{ - "base": { - "classloader.currentLoadedClass.count": 4011, - "classloader.totalLoadedClass.count": 4011, - "classloader.totalUnloadedClass.count": 0, - "cpu.availableProcessors": 8, - "cpu.systemLoadAverage": 1.65283203125, - "gc.G1 Old Generation.count": 0, - "gc.G1 Old Generation.time": 0, - "gc.G1 Young Generation.count": 2, - "gc.G1 Young Generation.time": 8, - "jvm.uptime": 478733, - "memory.committedHeap": 268435456, - "memory.maxHeap": 4294967296, - "memory.usedHeap": 18874368, - "thread.count": 11, - "thread.daemon.count": 4, - "thread.max.count": 11 - }, - "vendor": { - "grpc.requests.count": 0, - "grpc.requests.meter": { - "count": 0, - "meanRate": 0, - "oneMinRate": 0, - "fiveMinRate": 0, - "fifteenMinRate": 0 - }, - "requests.count": 5, - "requests.meter": { - "count": 5, - "meanRate": 0.01046407983617782, - "oneMinRate": 0.0023897243038835964, - "fiveMinRate": 0.003944597070306631, - "fifteenMinRate": 0.0023808575122958794 - } - } -} -``` - -## Build the Docker Image - -```sh -docker build -t employee-app . -``` - -## Start the application with Docker - -```sh -docker run --rm -p 8080:8080 employee-app:latest -``` - -Exercise the application as described above. - -## Deploy the application to Kubernetes - -```txt -kubectl cluster-info # Verify which cluster -kubectl get pods # Verify connectivity to cluster -kubectl create -f app.yaml # Deply application -kubectl get service employee-app # Get service info -``` - - -### Oracle DB Credentials -You can connect to two different datastores for the back end application. - Just fill in the application.yaml files. To use an ArrayList as the data store, - simply set `drivertype` to `Array`. To connect to an Oracle database, you must - set all the values: `user`, `password`, `hosturl`, and `drivertype`. - For Oracle, the `drivertype` should be set to `Oracle`. - -**Sample `application.yaml`** -```yaml -app: - user: - password: - hosturl: :/. - drivertype: Array - - server: - port: 8080 - host: 0.0.0.0 -``` - -## Create the database objects - -1. Create a connection to your Oracle Database using sqlplus or SQL Developer. - See https://docs.cloud.oracle.com/iaas/Content/Database/Tasks/connectingDB.htm. -2. Create the database objects: - -```sql -CREATE TABLE EMPLOYEE ( - ID INTEGER NOT NULL, - FIRSTNAME VARCHAR(100), - LASTNAME VARCHAR(100), - EMAIL VARCHAR(100), - PHONE VARCHAR(100), - BIRTHDATE VARCHAR(10), - TITLE VARCHAR(100), - DEPARTMENT VARCHAR(100), - PRIMARY KEY (ID) - ); -``` - -```sql -CREATE SEQUENCE EMPLOYEE_SEQ - START WITH 100 - INCREMENT BY 1; -``` - -```sql -INSERT INTO EMPLOYEE (ID, FIRSTNAME, LASTNAME, EMAIL, PHONE, BIRTHDATE, TITLE, DEPARTMENT) VALUES (EMPLOYEE_SEQ.nextVal, 'Hugh', 'Jast', 'Hugh.Jast@example.com', '730-555-0100', '1970-11-28', 'National Data Strategist', 'Mobility'); - -INSERT INTO EMPLOYEE (ID, FIRSTNAME, LASTNAME, EMAIL, PHONE, BIRTHDATE, TITLE, DEPARTMENT) VALUES (EMPLOYEE_SEQ.nextVal, 'Toy', 'Herzog', 'Toy.Herzog@example.com', '769-555-0102', '1961-08-08', 'Dynamic Operations Manager', 'Paradigm'); - -INSERT INTO EMPLOYEE (ID, FIRSTNAME, LASTNAME, EMAIL, PHONE, BIRTHDATE, TITLE, DEPARTMENT) VALUES (EMPLOYEE_SEQ.nextVal, 'Reed', 'Hahn', 'Reed.Hahn@example.com', '429-555-0153', '1977-02-05', 'Future Directives Facilitator', 'Quality'); - -INSERT INTO EMPLOYEE (ID, FIRSTNAME, LASTNAME, EMAIL, PHONE, BIRTHDATE, TITLE, DEPARTMENT) VALUES (EMPLOYEE_SEQ.nextVal, 'Novella', 'Bahringer', 'Novella.Bahringer@example.com', '293-596-3547', '1961-07-25', 'Principal Factors Architect', 'Division'); - -INSERT INTO EMPLOYEE (ID, FIRSTNAME, LASTNAME, EMAIL, PHONE, BIRTHDATE, TITLE, DEPARTMENT) VALUES (EMPLOYEE_SEQ.nextVal, 'Zora', 'Sawayn', 'Zora.Sawayn@example.com', '923-555-0161', '1978-03-18', 'Dynamic Marketing Designer', 'Security'); - -INSERT INTO EMPLOYEE (ID, FIRSTNAME, LASTNAME, EMAIL, PHONE, BIRTHDATE, TITLE, DEPARTMENT) VALUES (EMPLOYEE_SEQ.nextVal, 'Cordia', 'Willms', 'Cordia.Willms@example.com', '778-555-0187', '1989-03-31', 'Human Division Representative', 'Optimization'); -``` \ No newline at end of file diff --git a/examples/employee-app/app.yaml b/examples/employee-app/app.yaml deleted file mode 100644 index 0d0a40ceaaa..00000000000 --- a/examples/employee-app/app.yaml +++ /dev/null @@ -1,63 +0,0 @@ -# -# Copyright (c) 2019, 2021 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. -# - -kind: Service -apiVersion: v1 -metadata: - name: helidon-examples-employee-app - labels: - app: helidon-examples-employee-app -spec: - type: NodePort - selector: - app: helidon-examples-employee-app - ports: - - port: 8080 - targetPort: 8080 - name: http ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: helidon-examples-employee-app -spec: - replicas: 1 - template: - metadata: - labels: - app: helidon-examples-employee-app - version: v1 - spec: - containers: - - name: helidon-examples-employee-app - image: helidon-examples-employee-app - imagePullPolicy: IfNotPresent - ports: - - containerPort: 8080 ---- -apiVersion: v1 -kind: Service -metadata: - name: helidon-examples-employee-app - labels: - app: helidon-examples-employee-app -spec: - type: LoadBalancer - ports: - - port: 80 - targetPort: 8080 - selector: - app: helidon-examples-employee-app \ No newline at end of file diff --git a/examples/employee-app/pom.xml b/examples/employee-app/pom.xml deleted file mode 100644 index 29009f7c42b..00000000000 --- a/examples/employee-app/pom.xml +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../applications/se/pom.xml - - io.helidon.examples.employee - helidon-examples-employee-app - Helidon Examples Employee App - - - io.helidon.examples.employee.Main - - - - - io.helidon.integrations.db - ojdbc - - - com.oracle.database.jdbc - ucp - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver.observe - helidon-webserver-observe - - - io.helidon.webserver - helidon-webserver-static-content - - - io.helidon.http.media - helidon-http-media-jsonb - - - io.helidon.config - helidon-config-yaml - - - io.helidon.health - helidon-health-checks - - - io.helidon.webserver.observe - helidon-webserver-observe-metrics - runtime - - - io.helidon.metrics - helidon-metrics-system-meters - runtime - - - io.helidon.dbclient - helidon-dbclient - - - io.helidon.dbclient - helidon-dbclient-jdbc - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - - diff --git a/examples/employee-app/src/main/java/io/helidon/examples/employee/Employee.java b/examples/employee-app/src/main/java/io/helidon/examples/employee/Employee.java deleted file mode 100644 index f61e587defb..00000000000 --- a/examples/employee-app/src/main/java/io/helidon/examples/employee/Employee.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.employee; - -import java.util.UUID; - -import jakarta.json.bind.annotation.JsonbCreator; -import jakarta.json.bind.annotation.JsonbProperty; -/** - * Represents an employee. - */ -public final class Employee { - - private final String id; - private final String firstName; - private final String lastName; - private final String email; - private final String phone; - private final String birthDate; - private final String title; - private final String department; - - /**Creates a new Employee. - * @param id The employee ID. - * @param firstName The employee first name. - * @param lastName The employee lastName. - * @param email The employee email. - * @param phone The employee phone. - * @param birthDate The employee birthDatee. - * @param title The employee title. - * @param department The employee department.*/ - @SuppressWarnings("checkstyle:ParameterNumber") - private Employee(String id, String firstName, String lastName, String email, String phone, String birthDate, - String title, String department) { - this.id = id; - this.firstName = firstName; - this.lastName = lastName; - this.email = email; - this.phone = phone; - this.birthDate = birthDate; - this.title = title; - this.department = department; - } - - /** - * Creates a new employee. This method helps to parse the json parameters in the requests. - * @param id The employee ID. If the employee ID is null or empty generates a new ID. - * @param firstName The employee first name. - * @param lastName The employee lastName. - * @param email The employee email. - * @param phone The employee phone. - * @param birthDate The employee birthDatee. - * @param title The employee title. - * @param department The employee department. - * @return A new employee object - */ - @JsonbCreator - @SuppressWarnings("checkstyle:ParameterNumber") - public static Employee of(@JsonbProperty("id") String id, @JsonbProperty("firstName") String firstName, - @JsonbProperty("lastName") String lastName, @JsonbProperty("email") String email, - @JsonbProperty("phone") String phone, @JsonbProperty("birthDate") String birthDate, - @JsonbProperty("title") String title, @JsonbProperty("department") String department) { - if (id == null || id.trim().equals("")) { - id = UUID.randomUUID().toString(); - } - Employee e = new Employee(id, firstName, lastName, email, phone, birthDate, title, department); - return e; - } - - /** - * Returns the employee ID. - * @return the ID - */ - public String getId() { - return this.id; - } - - /** - * Returns the employee first name. - * @return The first name - */ - public String getFirstName() { - return this.firstName; - } - - /** - * Returns the employee last name. - * @return The last name - */ - public String getLastName() { - return this.lastName; - } - - /** - * Returns the employee e-mail. - * @return The email - */ - public String getEmail() { - return this.email; - } - - /** - * Returns the employee phone. - * @return The phone - */ - public String getPhone() { - return this.phone; - } - - /** - * Returns the employee birthdate. - * @return The birthdate - */ - public String getBirthDate() { - return this.birthDate; - } - - /** - * Returns the employee title. - * @return The title - */ - public String getTitle() { - return this.title; - } - - /** - * Returns the employee department. - * @return The department - */ - public String getDepartment() { - return this.department; - } - - @Override - public String toString() { - return "ID: " + id + " First Name: " + firstName + " Last Name: " + lastName + " EMail: " + email + " Phone: " - + phone + " Birth Date: " + birthDate + " Title: " + title + " Department: " + department; - } - -} diff --git a/examples/employee-app/src/main/java/io/helidon/examples/employee/EmployeeRepository.java b/examples/employee-app/src/main/java/io/helidon/examples/employee/EmployeeRepository.java deleted file mode 100644 index b53cef37ed2..00000000000 --- a/examples/employee-app/src/main/java/io/helidon/examples/employee/EmployeeRepository.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.employee; - -import java.util.List; -import java.util.Optional; - -import io.helidon.config.Config; - -/** - * Interface for Data Access Objects. - */ -public interface EmployeeRepository { - - /** - * Create a new employeeRepository instance using one of the two implementations - * {@link EmployeeRepositoryImpl} or {@link EmployeeRepositoryImplDB} depending - * on the specified driver type. - * - * @param driverType Represents the driver type. It can be Array or Oracle. - * @param config Contains the application configuration specified in the - * application.yaml file. - * @return The employee repository implementation. - */ - static EmployeeRepository create(String driverType, Config config) { - return switch (driverType) { - case "Database" -> new EmployeeRepositoryImplDB(config); - default -> - // Array is default - new EmployeeRepositoryImpl(); - }; - } - - /** - * Returns the list of the employees. - * - * @return The collection of all the employee objects - */ - List getAll(); - - /** - * Returns the list of the employees that match with the specified lastName. - * - * @param lastName Represents the last name value for the search. - * @return The collection of the employee objects that match with the specified - * lastName - */ - List getByLastName(String lastName); - - /** - * Returns the list of the employees that match with the specified title. - * - * @param title Represents the title value for the search - * @return The collection of the employee objects that match with the specified - * title - */ - List getByTitle(String title); - - /** - * Returns the list of the employees that match with the specified department. - * - * @param department Represents the department value for the search. - * @return The collection of the employee objects that match with the specified - * department - */ - List getByDepartment(String department); - - /** - * Add a new employee. - * - * @param employee returns the employee object including the ID generated. - * @return the employee object including the ID generated - */ - Employee save(Employee employee); // Add new employee - - /** - * Update an existing employee. - * - * @param updatedEmployee The employee object with the values to update - * @param id The employee ID - * @return number of updated records - */ - long update(Employee updatedEmployee, String id); - - /** - * Delete an employee by ID. - * - * @param id The employee ID - * @return number of deleted records - */ - long deleteById(String id); - - /** - * Get an employee by ID. - * - * @param id The employee ID - * @return The employee object if the employee is found - */ - Optional getById(String id); -} diff --git a/examples/employee-app/src/main/java/io/helidon/examples/employee/EmployeeRepositoryImpl.java b/examples/employee-app/src/main/java/io/helidon/examples/employee/EmployeeRepositoryImpl.java deleted file mode 100644 index e5641fc5852..00000000000 --- a/examples/employee-app/src/main/java/io/helidon/examples/employee/EmployeeRepositoryImpl.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.employee; - -import java.io.InputStream; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.CopyOnWriteArrayList; - -import jakarta.json.bind.Jsonb; -import jakarta.json.bind.JsonbBuilder; -import jakarta.json.bind.JsonbConfig; - -/** - * Implementation of the {@link EmployeeRepository}. This implementation uses a - * mock database written with in-memory ArrayList classes. - * The strings id, name, and other search strings are validated before being - * passed to the methods in this class. - */ -public final class EmployeeRepositoryImpl implements EmployeeRepository { - - private final CopyOnWriteArrayList eList = new CopyOnWriteArrayList<>(); - - /** - * To load the initial data, parses the content of employee.json - * file located in the resources directory to a list of Employee - * objects. - */ - public EmployeeRepositoryImpl() { - JsonbConfig config = new JsonbConfig().withFormatting(Boolean.TRUE); - try (Jsonb jsonb = JsonbBuilder.create(config); - InputStream jsonFile = EmployeeRepositoryImpl.class.getResourceAsStream("/employees.json")) { - Employee[] employees = jsonb.fromJson(jsonFile, Employee[].class); - eList.addAll(Arrays.asList(employees)); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - @Override - public List getByLastName(String name) { - return eList.stream() - .filter((e) -> (e.getLastName().contains(name))) - .toList(); - } - - @Override - public List getByTitle(String title) { - return eList.stream() - .filter((e) -> (e.getTitle().contains(title))) - .toList(); - } - - @Override - public List getByDepartment(String department) { - return eList.stream() - .filter((e) -> (e.getDepartment().contains(department))) - .toList(); - } - - @Override - public List getAll() { - return eList; - } - - @Override - public Optional getById(String id) { - return eList.stream().filter(e -> e.getId().equals(id)).findFirst(); - } - - @Override - public Employee save(Employee employee) { - Employee nextEmployee = Employee.of(null, - employee.getFirstName(), - employee.getLastName(), - employee.getEmail(), - employee.getPhone(), - employee.getBirthDate(), - employee.getTitle(), - employee.getDepartment()); - eList.add(nextEmployee); - return nextEmployee; - } - - @Override - public long update(Employee updatedEmployee, String id) { - deleteById(id); - Employee e = Employee.of(id, updatedEmployee.getFirstName(), updatedEmployee.getLastName(), - updatedEmployee.getEmail(), updatedEmployee.getPhone(), updatedEmployee.getBirthDate(), - updatedEmployee.getTitle(), updatedEmployee.getDepartment()); - eList.add(e); - return 1L; - } - - @Override - public long deleteById(String id) { - return eList.stream() - .filter(e -> e.getId().equals(id)) - .findFirst() - .map(eList::remove) - .map(it -> 1L) - .orElse(0L); - } -} diff --git a/examples/employee-app/src/main/java/io/helidon/examples/employee/EmployeeRepositoryImplDB.java b/examples/employee-app/src/main/java/io/helidon/examples/employee/EmployeeRepositoryImplDB.java deleted file mode 100644 index e95694c0bca..00000000000 --- a/examples/employee-app/src/main/java/io/helidon/examples/employee/EmployeeRepositoryImplDB.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2019, 2024 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.employee; - -import java.util.List; -import java.util.Optional; -import java.util.stream.Stream; - -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbRow; -import io.helidon.dbclient.jdbc.JdbcClientBuilder; - -/** - * Implementation of the {@link EmployeeRepository}. This implementation uses an - * Oracle database to persist the Employee objects. - */ -final class EmployeeRepositoryImplDB implements EmployeeRepository { - - private final DbClient dbClient; - - /** - * Creates the database connection using the parameters specified in the - * application.yaml file located in the resources directory. - * - * @param config Represents the application configuration. - */ - EmployeeRepositoryImplDB(Config config) { - String url = "jdbc:oracle:thin:@"; - String driver = "oracle.jdbc.driver.OracleDriver"; - - String dbUserName = config.get("app.user").asString().orElse("sys as SYSDBA"); - String dbUserPassword = config.get("app.password").asString().orElse("changeit"); - String dbHostURL = config.get("app.hosturl").asString().orElse("localhost:1521/xe"); - - try { - Class.forName(driver); - } catch (Exception sqle) { - sqle.printStackTrace(); - } - - // now we create the DB Client - explicitly use JDBC, so we can - // configure JDBC specific configuration - dbClient = JdbcClientBuilder.create() - .url(url + dbHostURL) - .username(dbUserName) - .password(dbUserPassword) - .build(); - } - - @Override - public List getAll() { - String queryStr = "SELECT * FROM EMPLOYEE"; - - return toEmployeeList(dbClient.execute().query(queryStr)); - } - - @Override - public List getByLastName(String name) { - String queryStr = "SELECT * FROM EMPLOYEE WHERE LASTNAME LIKE ?"; - - return toEmployeeList(dbClient.execute().query(queryStr, name)); - } - - @Override - public List getByTitle(String title) { - String queryStr = "SELECT * FROM EMPLOYEE WHERE TITLE LIKE ?"; - - return toEmployeeList(dbClient.execute().query(queryStr, title)); - } - - @Override - public List getByDepartment(String department) { - String queryStr = "SELECT * FROM EMPLOYEE WHERE DEPARTMENT LIKE ?"; - - return toEmployeeList(dbClient.execute().query(queryStr, department)); - } - - @Override - public Employee save(Employee employee) { - String insertTableSQL = "INSERT INTO EMPLOYEE " - + "(ID, FIRSTNAME, LASTNAME, EMAIL, PHONE, BIRTHDATE, TITLE, DEPARTMENT) " - + "VALUES(EMPLOYEE_SEQ.NEXTVAL,?,?,?,?,?,?,?)"; - - dbClient.execute() - .createInsert(insertTableSQL) - .addParam(employee.getFirstName()) - .addParam(employee.getLastName()) - .addParam(employee.getEmail()) - .addParam(employee.getPhone()) - .addParam(employee.getBirthDate()) - .addParam(employee.getTitle()) - .addParam(employee.getDepartment()) - .execute(); - // let's always return the employee once the insert finishes - return employee; - } - - @Override - public long deleteById(String id) { - String deleteRowSQL = "DELETE FROM EMPLOYEE WHERE ID=?"; - - return dbClient.execute().delete(deleteRowSQL, id); - } - - @Override - public Optional getById(String id) { - String queryStr = "SELECT * FROM EMPLOYEE WHERE ID =?"; - - return dbClient.execute() - .get(queryStr, id) - .map(row -> row.as(Employee.class)); - } - - @Override - public long update(Employee updatedEmployee, String id) { - String updateTableSQL = "UPDATE EMPLOYEE SET FIRSTNAME=?, LASTNAME=?, EMAIL=?, PHONE=?, BIRTHDATE=?, TITLE=?, " - + "DEPARTMENT=? WHERE ID=?"; - - return dbClient.execute() - .createUpdate(updateTableSQL) - .addParam(updatedEmployee.getFirstName()) - .addParam(updatedEmployee.getLastName()) - .addParam(updatedEmployee.getEmail()) - .addParam(updatedEmployee.getPhone()) - .addParam(updatedEmployee.getBirthDate()) - .addParam(updatedEmployee.getTitle()) - .addParam(updatedEmployee.getDepartment()) - .addParam(Integer.parseInt(id)) - .execute(); - } - - private static List toEmployeeList(Stream rows) { - return rows.map(EmployeeDbMapper::read).toList(); - } - - private static final class EmployeeDbMapper { - private EmployeeDbMapper() { - } - - static Employee read(DbRow row) { - // map named columns to an object - return Employee.of( - row.column("ID").get(String.class), - row.column("FIRSTNAME").get(String.class), - row.column("LASTNAME").get(String.class), - row.column("EMAIL").get(String.class), - row.column("PHONE").get(String.class), - row.column("BIRTHDATE").get(String.class), - row.column("TITLE").get(String.class), - row.column("DEPARTMENT").get(String.class) - ); - } - } -} diff --git a/examples/employee-app/src/main/java/io/helidon/examples/employee/EmployeeService.java b/examples/employee-app/src/main/java/io/helidon/examples/employee/EmployeeService.java deleted file mode 100644 index 85360b6d7d7..00000000000 --- a/examples/employee-app/src/main/java/io/helidon/examples/employee/EmployeeService.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.employee; - -import java.util.HashMap; -import java.util.Map; -import java.util.logging.Logger; - -import io.helidon.config.Config; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -/** - * The Employee service endpoints. - *
        - *
      • Get all employees: {@code curl -X GET http://localhost:8080/employees}
      • - *
      • Get employee by id: {@code curl -X GET http://localhost:8080/employees/{id}}
      • - *
      • Add employee {@code curl -X POST http://localhost:8080/employees/{id}}
      • - *
      • Update employee by id {@code curl -X PUT http://localhost:8080/employees/{id}}
      • - *
      • Delete employee by id {@code curl -X DELETE http://localhost:8080/employees/{id}}
      • - *
      - * The message is returned as a JSON object - */ -public class EmployeeService implements HttpService { - private final EmployeeRepository employees; - private static final Logger LOGGER = Logger.getLogger(EmployeeService.class.getName()); - - EmployeeService(Config config) { - String driverType = config.get("app.drivertype").asString().orElse("Array"); - employees = EmployeeRepository.create(driverType, config); - } - - /** - * A service registers itself by updating the routine rules. - * - * @param rules the routing rules. - */ - @Override - public void routing(HttpRules rules) { - rules.get("/", this::getAll) - .get("/lastname/{name}", this::getByLastName) - .get("/department/{name}", this::getByDepartment) - .get("/title/{name}", this::getByTitle) - .post("/", this::save) - .get("/{id}", this::getEmployeeById) - .put("/{id}", this::update) - .delete("/{id}", this::delete); - } - - /** - * Gets all the employees. - * - * @param request the server request - * @param response the server response - */ - private void getAll(ServerRequest request, ServerResponse response) { - LOGGER.fine("getAll"); - - response.send(employees.getAll()); - } - - /** - * Gets the employees by the last name specified in the parameter. - * - * @param request the server request - * @param response the server response - */ - private void getByLastName(ServerRequest request, ServerResponse response) { - LOGGER.fine("getByLastName"); - - String name = request.path().pathParameters().get("name"); - // Invalid query strings handled in isValidQueryStr. Keeping DRY - if (isValidQueryStr(response, name)) { - response.send(employees.getByLastName(name)); - } - } - - /** - * Gets the employees by the title specified in the parameter. - * - * @param request the server request - * @param response the server response - */ - private void getByTitle(ServerRequest request, ServerResponse response) { - LOGGER.fine("getByTitle"); - - String title = request.path().pathParameters().get("name"); - if (isValidQueryStr(response, title)) { - response.send(employees.getByTitle(title)); - } - } - - /** - * Gets the employees by the department specified in the parameter. - * - * @param request the server request - * @param response the server response - */ - private void getByDepartment(ServerRequest request, ServerResponse response) { - LOGGER.fine("getByDepartment"); - - String department = request.path().pathParameters().get("name"); - if (isValidQueryStr(response, department)) { - response.send(employees.getByDepartment(department)); - } - } - - /** - * Gets the employees by the ID specified in the parameter. - * - * @param request the server request - * @param response the server response - */ - private void getEmployeeById(ServerRequest request, ServerResponse response) { - LOGGER.fine("getEmployeeById"); - - String id = request.path().pathParameters().get("id"); - // If invalid, response handled in isValidId. Keeping DRY - if (isValidQueryStr(response, id)) { - employees.getById(id) - .ifPresentOrElse(response::send, () -> response.status(404).send()); - } - } - - /** - * Saves a new employee. - * - * @param request the server request - * @param response the server response - */ - private void save(ServerRequest request, ServerResponse response) { - LOGGER.fine("save"); - - Employee employee = request.content().as(Employee.class); - employees.save(Employee.of(null, - employee.getFirstName(), - employee.getLastName(), - employee.getEmail(), - employee.getPhone(), - employee.getBirthDate(), - employee.getTitle(), - employee.getDepartment())); - response.status(201).send(); - } - - /** - * Updates an existing employee. - * - * @param request the server request - * @param response the server response - */ - private void update(ServerRequest request, ServerResponse response) { - LOGGER.fine("update"); - - String id = request.path().pathParameters().get("id"); - if (isValidQueryStr(response, id)) { - if (employees.update(request.content().as(Employee.class), id) == 0) { - response.status(404).send(); - } else { - response.status(204).send(); - } - } - } - - /** - * Deletes an existing employee. - * - * @param request the server request - * @param response the server response - */ - private void delete(ServerRequest request, ServerResponse response) { - LOGGER.fine("delete"); - - String id = request.path().pathParameters().get("id"); - if (isValidQueryStr(response, id)) { - if (employees.deleteById(id) == 0) { - response.status(404).send(); - } else { - response.status(204).send(); - } - } - } - - /** - * Validates the parameter. - * - * @param response the server response - * @param name employee name - * @return true if valid, false otherwise - */ - private boolean isValidQueryStr(ServerResponse response, String name) { - Map errorMessage = new HashMap<>(); - if (name == null || name.isEmpty() || name.length() > 100) { - errorMessage.put("errorMessage", "Invalid query string"); - response.status(400).send(errorMessage); - return false; - } else { - return true; - } - } -} diff --git a/examples/employee-app/src/main/java/io/helidon/examples/employee/Main.java b/examples/employee-app/src/main/java/io/helidon/examples/employee/Main.java deleted file mode 100644 index 126794cb700..00000000000 --- a/examples/employee-app/src/main/java/io/helidon/examples/employee/Main.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.employee; - -import io.helidon.config.Config; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.http.HttpRouting; -import io.helidon.webserver.staticcontent.StaticContentService; - -/** - * Simple Employee rest application. - */ -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) { - WebServerConfig.Builder builder = WebServer.builder(); - setup(builder); - WebServer server = builder.build().start(); - System.out.printf(""" - WEB server is up! - Web client at: http://localhost:%1$d/public/index.html - """, server.port()); - } - - /** - * Set up the server. - * - * @param server server builder - */ - static void setup(WebServerConfig.Builder server) { - - // load logging configuration - LogConfig.configureRuntime(); - - // By default, this will pick up application.yaml from the classpath - Config config = Config.create(); - - // Get webserver config from the "server" section of application.yaml and JSON support registration - server.config(config.get("server")) - .routing(r -> routing(r, config)); - } - - /** - * Setup routing. - * - * @param routing routing builder - * @param config configuration of this server - */ - static void routing(HttpRouting.Builder routing, Config config) { - routing.register("/public", StaticContentService.builder("public") - .welcomeFileName("index.html")) - .register("/employees", new EmployeeService(config)); - } - -} diff --git a/examples/employee-app/src/main/java/io/helidon/examples/employee/package-info.java b/examples/employee-app/src/main/java/io/helidon/examples/employee/package-info.java deleted file mode 100644 index af67b8932d8..00000000000 --- a/examples/employee-app/src/main/java/io/helidon/examples/employee/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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. - */ - -/** - * Employee example application - *

      - * Start with {@link io.helidon.examples.employee.Main} class. - * - * @see io.helidon.examples.employee.Main - */ -package io.helidon.examples.employee; diff --git a/examples/employee-app/src/main/resources/application.yaml b/examples/employee-app/src/main/resources/application.yaml deleted file mode 100644 index 25baa52deeb..00000000000 --- a/examples/employee-app/src/main/resources/application.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# -# Copyright (c) 2019, 2020 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. -# - -app: - # database user, such as "system" - user: - # database password - password: - # host url - remove to use the default of Oracle XE (localhost:1521/XE) - hosturl: :/. - # switch to "Database" to use database. Uses in-memory structure otherwise - drivertype: Array - -server: - port: 8080 - host: 0.0.0.0 diff --git a/examples/employee-app/src/main/resources/employees.json b/examples/employee-app/src/main/resources/employees.json deleted file mode 100644 index bce81a67cdd..00000000000 --- a/examples/employee-app/src/main/resources/employees.json +++ /dev/null @@ -1,402 +0,0 @@ -[ - { - "id": "84240085-7c68-4930-8fb3-2f9be11b6810", - "firstName": "Hugh", - "lastName": "Jast", - "email": "Hugh.Jast@example.com", - "phone": "730-715-4446", - "birthDate": "1970-11-28", - "title": "National Data Strategist", - "department": "Mobility" - }, - { - "id": "f9971d4f-5b30-4553-8d5c-2116f9a58264", - "firstName": "Toy", - "lastName": "Herzog", - "email": "Toy.Herzog@example.com", - "phone": "769-569-1789", - "birthDate": "1961-08-08", - "title": "Dynamic Operations Manager", - "department": "Paradigm" - }, - { - "id": "5b8a19f4-8ccf-49b2-9d68-9644c29eb0f0", - "firstName": "Reed", - "lastName": "Hahn", - "email": "Reed.Hahn@example.com", - "phone": "429-071-2018", - "birthDate": "1977-02-05", - "title": "Future Directives Facilitator", - "department": "Quality" - }, - { - "id": "07700c37-a418-4762-9d7e-831dc1ea797e", - "firstName": "Novella", - "lastName": "Bahringer", - "email": "Novella.Bahringer@example.com", - "phone": "293-596-3547", - "birthDate": "1961-07-25", - "title": "Principal Factors Architect", - "department": "Division" - }, - { - "id": "11c9cf10-fbbd-4ffa-8ef6-038a4bce9713", - "firstName": "Zora", - "lastName": "Sawayn", - "email": "Zora.Sawayn@example.com", - "phone": "923-814-0502", - "birthDate": "1978-03-18", - "title": "Dynamic Marketing Designer", - "department": "Security" - }, - { - "id": "19737839-97a8-4b07-b52b-828db9f98e0a", - "firstName": "Cordia", - "lastName": "Willms", - "email": "Cordia.Willms@example.com", - "phone": "778-821-3941", - "birthDate": "1989-03-31", - "title": "Human Division Representative", - "department": "Optimization" - }, - { - "id": "3e8822ea-6a3d-4855-9e79-d918c7733ec5", - "firstName": "Clair", - "lastName": "Bartoletti", - "email": "Clair.Bartoletti@example.com", - "phone": "647-896-8993", - "birthDate": "1986-01-04", - "title": "Customer Marketing Executive", - "department": "Factors" - }, - { - "id": "2937368c-2dd9-4e86-908c-4a39a27bde39", - "firstName": "Joe", - "lastName": "Beahan", - "email": "Joe.Beahan@example.com", - "phone": "548-890-6181", - "birthDate": "1990-07-11", - "title": "District Group Specialist", - "department": "Program" - }, - { - "id": "e74f77d9-69f2-48ac-8a7f-b90a70bdeeea", - "firstName": "Daphney", - "lastName": "Feest", - "email": "Daphney.Feest@example.com", - "phone": "143-967-7041", - "birthDate": "1984-03-26", - "title": "Dynamic Mobility Consultant", - "department": "Metrics" - }, - { - "id": "154df9ce-1e86-47e1-a770-306a26cd62e9", - "firstName": "Janessa", - "lastName": "Wyman", - "email": "Janessa.Wyman@example.com", - "phone": "498-186-9009", - "birthDate": "1985-09-06", - "title": "Investor Brand Associate", - "department": "Markets" - }, - { - "id": "92c8b250-786d-47eb-a7f5-eabe3d6e39c2", - "firstName": "Mara", - "lastName": "Roob", - "email": "Mara.Roob@example.com", - "phone": "962-540-9884", - "birthDate": "1975-05-11", - "title": "Legacy Assurance Engineer", - "department": "Usability" - }, - { - "id": "9e046988-c561-417f-9696-f14608c00bd4", - "firstName": "Brennon", - "lastName": "Bernhard", - "email": "Brennon.Bernhard@example.com", - "phone": "395-224-9853", - "birthDate": "1963-12-05", - "title": "Product Web Officer", - "department": "Interactions" - }, - { - "id": "490a1262-15a7-4606-84ae-6e02f6671c13", - "firstName": "Amya", - "lastName": "Bernier", - "email": "Amya.Bernier@example.com", - "phone": "563-562-4171", - "birthDate": "1972-06-23", - "title": "Global Tactics Planner", - "department": "Program" - }, - { - "id": "60bad2bd-a71d-4494-bff1-09940809c51c", - "firstName": "Claud", - "lastName": "Boehm", - "email": "Claud.Boehm@example.com", - "phone": "089-073-7399", - "birthDate": "1965-02-27", - "title": "National Marketing Associate", - "department": "Directives" - }, - { - "id": "0f48efc9-a820-42c0-9d8f-2ae962d0ce7b", - "firstName": "Nyah", - "lastName": "Schowalter", - "email": "Nyah.Schowalter@example.com", - "phone": "823-063-7120", - "birthDate": "1969-02-19", - "title": "Dynamic Communications Assistant", - "department": "Metrics" - }, - { - "id": "3323fc7a-dcb9-4cfe-9e59-4160290c1ccc", - "firstName": "Imogene", - "lastName": "Bernhard", - "email": "Imogene.Bernhard@example.com", - "phone": "747-970-6062", - "birthDate": "1958-02-09", - "title": "Dynamic Assurance Supervisor", - "department": "Paradigm" - }, - { - "id": "44c5fe14-d1a3-416a-aab8-f569c3ed2eca", - "firstName": "Chanel", - "lastName": "Kuhlman", - "email": "Chanel.Kuhlman@example.com", - "phone": "882-145-9513", - "birthDate": "1985-03-03", - "title": "District Paradigm Representative", - "department": "Integration" - }, - { - "id": "8235e91e-3024-47f8-afd8-577617cfb8bf", - "firstName": "Cierra", - "lastName": "Morar", - "email": "Cierra.Morar@example.com", - "phone": "273-607-2209", - "birthDate": "1965-01-25", - "title": "Dynamic Data Planner", - "department": "Paradigm" - }, - { - "id": "5733bed9-ce41-4ed5-8b29-9288318dd5a7", - "firstName": "Faye", - "lastName": "Grimes", - "email": "Faye.Grimes@example.com", - "phone": "750-139-1344", - "birthDate": "1962-08-21", - "title": "Central Applications Analyst", - "department": "Tactics" - }, - { - "id": "34956311-26fb-46b1-abf0-a95a08d929ea", - "firstName": "Doyle", - "lastName": "Rohan", - "email": "Doyle.Rohan@example.com", - "phone": "093-457-5621", - "birthDate": "1991-11-29", - "title": "Corporate Accountability Supervisor", - "department": "Applications" - }, - { - "id": "2e121065-431a-4ba2-aeb4-3919fcb7969a", - "firstName": "Jonathan", - "lastName": "Barrows", - "email": "Jonathan.Barrows@example.com", - "phone": "262-503-2161", - "birthDate": "1963-12-15", - "title": "Regional Configuration Liason", - "department": "Implementation" - }, - { - "id": "99d0603f-03cc-4dca-bebe-a711eaf14d77", - "firstName": "Myriam", - "lastName": "Luettgen", - "email": "Myriam.Luettgen@example.com", - "phone": "951-924-8295", - "birthDate": "1962-02-08", - "title": "Central Functionality Specialist", - "department": "Accountability" - }, - { - "id": "50653f57-3379-4bfd-9999-2ec86ab1131d", - "firstName": "Johnnie", - "lastName": "Schiller", - "email": "Johnnie.Schiller@example.com", - "phone": "534-025-2200", - "birthDate": "1965-04-11", - "title": "Principal Creative Developer", - "department": "Interactions" - }, - { - "id": "d93c7987-69c8-4333-99fe-d1561b338722", - "firstName": "Laila", - "lastName": "White", - "email": "Laila.White@example.com", - "phone": "468-939-2298", - "birthDate": "1956-01-04", - "title": "Corporate Optimization Engineer", - "department": "Assurance" - }, - { - "id": "ac90bb96-79e1-424a-94f6-90f7c01ea4b3", - "firstName": "Alessandra", - "lastName": "Becker", - "email": "Alessandra.Becker@example.com", - "phone": "081-724-0866", - "birthDate": "1984-08-12", - "title": "Central Identity Associate", - "department": "Quality" - }, - { - "id": "215f86fb-8434-4b75-8cc2-4bf731b71f6f", - "firstName": "Shannon", - "lastName": "McCullough", - "email": "Shannon.McCullough@example.com", - "phone": "101-995-1089", - "birthDate": "1989-02-25", - "title": "Global Data Engineer", - "department": "Division" - }, - { - "id": "f09f164c-7fc2-4afe-b9ae-29bc1c48b529", - "firstName": "Garnet", - "lastName": "Labadie", - "email": "Garnet.Labadie@example.com", - "phone": "147-954-6624", - "birthDate": "1990-01-01", - "title": "Senior Communications Producer", - "department": "Program" - }, - { - "id": "b16d7d13-e4ee-4293-bb2d-c79d98485ef0", - "firstName": "Mark", - "lastName": "Graham", - "email": "Mark.Graham@example.com", - "phone": "462-746-7388", - "birthDate": "1991-08-23", - "title": "Legacy Directives Agent", - "department": "Assurance" - }, - { - "id": "3ff0adc3-09e0-4490-900c-9d59dd622bd8", - "firstName": "Tristin", - "lastName": "Bayer", - "email": "Tristin.Bayer@example.com", - "phone": "882-044-3996", - "birthDate": "1964-03-26", - "title": "Internal Marketing Officer", - "department": "Intranet" - }, - { - "id": "c1e5e2ad-2ee9-4eb1-af9e-e9e17fe694bc", - "firstName": "Maurice", - "lastName": "Renner", - "email": "Maurice.Renner@example.com", - "phone": "383-435-0943", - "birthDate": "1973-11-05", - "title": "National Accountability Planner", - "department": "Accounts" - }, - { - "id": "06a0ac23-ff09-4f27-971d-1b901e5ff1c8", - "firstName": "Preston", - "lastName": "Stark", - "email": "Preston.Stark@example.com", - "phone": "080-698-9552", - "birthDate": "1994-02-02", - "title": "Corporate Program Orchestrator", - "department": "Integration" - }, - { - "id": "2443a803-39ec-435b-9bda-1bfdee716308", - "firstName": "Mabelle", - "lastName": "Herman", - "email": "Mabelle.Herman@example.com", - "phone": "778-672-2787", - "birthDate": "1956-11-30", - "title": "Human Identity Officer", - "department": "Integration" - }, - { - "id": "45d87394-7fb2-430a-9b65-714b5266b8a1", - "firstName": "Juvenal", - "lastName": "Swaniawski", - "email": "Juvenal.Swaniawski@example.com", - "phone": "349-906-2745", - "birthDate": "1963-11-17", - "title": "Future Program Planner", - "department": "Response" - }, - { - "id": "f0b4ec27-af12-4694-aee2-77a620c6fb5e", - "firstName": "Rachelle", - "lastName": "Okuneva", - "email": "Rachelle.Okuneva@example.com", - "phone": "134-565-3868", - "birthDate": "1992-05-27", - "title": "District Creative Architect", - "department": "Paradigm" - }, - { - "id": "7c4dc3be-6141-4ce2-8513-cee11e2708d1", - "firstName": "Macey", - "lastName": "Weissnat", - "email": "Macey.Weissnat@example.com", - "phone": "210-461-3749", - "birthDate": "1978-06-24", - "title": "Product Accountability Facilitator", - "department": "Data" - }, - { - "id": "c4282cf5-f10b-4752-b201-a1f6cb469212", - "firstName": "Ena", - "lastName": "Gerlach", - "email": "Ena.Gerlach@example.com", - "phone": "429-925-7634", - "birthDate": "1976-04-09", - "title": "Human Tactics Agent", - "department": "Creative" - }, - { - "id": "2b32bbbd-c4bb-426c-a759-1664f40db4c8", - "firstName": "Darrick", - "lastName": "Deckow", - "email": "Darrick.Deckow@example.com", - "phone": "549-222-4121", - "birthDate": "1956-10-25", - "title": "Lead Solutions Producer", - "department": "Metrics" - }, - { - "id": "65389ce1-d930-48ae-9347-49741496dc4e", - "firstName": "Palma", - "lastName": "Torp", - "email": "Palma.Torp@example.com", - "phone": "346-556-3517", - "birthDate": "1967-06-24", - "title": "Product Infrastructure Consultant", - "department": "Response" - }, - { - "id": "9cbaf350-0e00-4aaf-84a4-b348f75257ca", - "firstName": "Lucious", - "lastName": "Steuber", - "email": "Lucious.Steuber@example.com", - "phone": "977-372-2840", - "birthDate": "1961-11-24", - "title": "District Creative Supervisor", - "department": "Mobility" - }, - { - "id": "72de2181-3f3d-4b0d-a528-bc60a1aa0a12", - "firstName": "Kacey", - "lastName": "Kilback", - "email": "Kacey.Kilback@example.com", - "phone": "268-777-2011", - "birthDate": "1957-09-06", - "title": "Corporate Mobility Agent", - "department": "Infrastructure" - } -] \ No newline at end of file diff --git a/examples/employee-app/src/main/resources/logging.properties b/examples/employee-app/src/main/resources/logging.properties deleted file mode 100644 index 1102463530f..00000000000 --- a/examples/employee-app/src/main/resources/logging.properties +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright (c) 2019, 2024 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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 diff --git a/examples/employee-app/src/main/resources/public/EmployeeController.js b/examples/employee-app/src/main/resources/public/EmployeeController.js deleted file mode 100644 index e820be28cd9..00000000000 --- a/examples/employee-app/src/main/resources/public/EmployeeController.js +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (c) 2019, 2021 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. - */ -var server = "/"; - -function search (){ - var searchTerm = $("#searchText").val().trim(); - if (searchTerm != "") { - $("#people").show(); - $("#people").html("SEARCHING..."); - $.ajax({ - url: server + "employees/" + - $("#searchType").val() + "/" + - encodeURIComponent(searchTerm), - method: "GET" - }).done( - function(data) { - $("#people").empty(); - $("#people").hide(); - if (data.length == 0) { - $("#people").html(""); - $("#notFound").show(); - $("#notFound").html("No people found matching your search criteria"); - } else { - showResults(data); - } - $("#people").show(400, "swing"); - }); - } else { - loadEmployees(); - } -} - -$(function() { - $("#searchText").on("keyup", function(e) { - if (e.keyCode == 13) { - search (); - } - }); -}); - -function showResults(data){ - $("#people").hide(); - $("#people").empty(); - $("#notFound").hide(); - data.forEach(function(employee) { - var item = $(renderEmployees(employee)); - item.on("click", function() { - var detailItem = $(renderDetailEmployee(employee)); - $("#home").hide(); - $("#detail").empty(); - $("#notFound").hide(); - $("#detail").append(detailItem); - $("#people").hide( - 400, - "swing", - function() { - $("#detail").show() - }); - }); - $("#people").append(item); - }); -} - -function showEmployeeForm() { - $("#notFound").hide(); - $("#editForm").hide(); - $("#deleteButton").hide(); - $("#employeeForm").show(); - $("#formTitle").text("Add Employee"); - $("#home").hide(); - $("#people").hide(); -} - -function loadEmployees() { - $("#notFound").hide(); - $("#searchText").val(""); - $("#employeeForm").hide(); - $("#editForm").hide(); - $("#home").show(); - $("#people").show(); - $("#people").html("LOADING..."); - $.ajax({ - dataType: "json", - url: server + "employees", - method: "GET" - }).done(function(data) { - showResults(data); - $("#people").show(400, "swing"); - }); -} - - -function renderEmployees(employee){ - var template = $('#employees_tpl').html(); - Mustache.parse(template); - var rendered = Mustache.render(template, { - "firstName" : employee.firstName, - "lastName" : employee.lastName, - "title" : employee.title, - "department" : employee.department - }); - return rendered; -} - -function renderDetailEmployee(employee){ - var template = $('#detail_tpl').html(); - Mustache.parse(template); - var rendered = Mustache.render(template,{ - "id" : employee.id, - "firstName" : employee.firstName, - "lastName" : employee.lastName, - "email" : employee.email, - "birthDate" : employee.birthDate, - "phone" : employee.phone, - "title" : employee.title, - "department" : employee.department - }); - return rendered; -} - -function save() { - var employee = { - id: "", - firstName: $("#firstName").val(), - lastName: $("#lastName").val(), - email: $("#email").val(), - phone: $("#phone").val(), - birthDate: $("#birthDate").val(), - title: $("#title").val(), - department: $("#department").val() - }; - $.ajax({ - url: server + "employees", - method: "POST", - data: JSON.stringify(employee) - }).done(function(data) { - $("#detail").hide(); - $("#firstName").val(""); - $("#lastName").val(""); - $("#email").val(""); - $("#phone").val(""); - $("#birthDate").val(""); - $("#title").val(""); - $("#department").val(""); - loadEmployees(); - }); - -} - -function updateEmployee() { - var employee = { - id: $("#editId").val(), - firstName: $("#editFirstName").val(), - lastName: $("#editLastName").val(), - email: $("#editEmail").val(), - phone: $("#editPhone").val(), - birthDate: $("#editBirthDate").val(), - title: $("#editTitle").val(), - department: $("#editDepartment").val() - }; - $("#detail").html("UPDATING..."); - $.ajax({ - url: server + "employees/" + employee.id, - method: "PUT", - data: JSON.stringify(employee) - }).done(function(data) { - $("#detail").hide(); - loadEmployees(); - }); -} - -function deleteEmployee() { - var employee = { - firstName: $("#editFirstName").val(), - lastName: $("#editLastName").val(), - id: $("#editId").val() - }; - $('

      ').dialog({ - modal: true, - title: "Confirm Delete", - open: function() { - var markup = 'Are you sure you want to delete ' + - employee.firstName + ' ' + employee.lastName + - " employee?"; - $(this).html(markup); - }, - buttons: { - Ok: function() { - $("#detail").html("DELETING..."); - $(this).dialog("close"); - $.ajax({ - url: server + "employees/" + employee.id, - method: "DELETE" - }).done(function(data) { - $("#detail").hide(); - loadEmployees(); - }); - }, - Cancel: function() { - $(this).dialog("close"); - } - } - }); - -} diff --git a/examples/employee-app/src/main/resources/public/index.html b/examples/employee-app/src/main/resources/public/index.html deleted file mode 100644 index 8a202d95bc7..00000000000 --- a/examples/employee-app/src/main/resources/public/index.html +++ /dev/null @@ -1,399 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - -

      Cloud Employee App

      - - -
      -
      -
      LOADING...
      -
      -
      - - - - diff --git a/examples/employee-app/src/main/resources/public/nopic.png b/examples/employee-app/src/main/resources/public/nopic.png deleted file mode 100644 index 5967653cf93f2cb98fcad0eb9cf66be3bdd558dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3584 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 diff --git a/examples/employee-app/src/test/java/io/helidon/examples/employee/MainTest.java b/examples/employee-app/src/test/java/io/helidon/examples/employee/MainTest.java deleted file mode 100644 index ea331d04867..00000000000 --- a/examples/employee-app/src/test/java/io/helidon/examples/employee/MainTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.employee; - -import io.helidon.config.Config; -import io.helidon.http.Status; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.http.HttpRouting; -import io.helidon.webserver.testing.junit5.DirectClient; -import io.helidon.webserver.testing.junit5.RoutingTest; -import io.helidon.webserver.testing.junit5.SetUpRoute; - -import jakarta.json.JsonArray; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -@RoutingTest -public class MainTest { - - private final DirectClient client; - - public MainTest(DirectClient client) { - this.client = client; - } - - @SetUpRoute - public static void setup(HttpRouting.Builder routing) { - Main.routing(routing, Config.empty()); - } - - @Test - public void testEmployees() { - try (Http1ClientResponse response = client.get("/employees") - .request()) { - assertThat("HTTP response2", response.status(), is(Status.OK_200)); - assertThat(response.as(JsonArray.class).size(), is(40)); - } - } - -} diff --git a/examples/graphql/basics/README.md b/examples/graphql/basics/README.md deleted file mode 100644 index eb43abe7996..00000000000 --- a/examples/graphql/basics/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# Helidon GraphQL Basic Example - -This example shows the basics of using Helidon SE GraphQL. The example -manually creates a GraphQL Schema using the [GraphQL Java](https://github.com/graphql-java/graphql-java) API. - -## Build and run - -Start the application: - -```shell -mvn package -java -jar target/helidon-examples-graphql-basics.jar -``` - -Note the port number reported by the application. - -Probe the GraphQL endpoints: - -1. Hello word endpoint: - - ```shell - curl -X POST http://127.0.0.1:PORT/graphql -d '{"query":"query { hello }"}' - - "data":{"hello":"world"}} - ``` - -1. Hello in different languages - - ```shell - curl -X POST http://127.0.0.1:PORT/graphql -d '{"query":"query { helloInDifferentLanguages }"}' - - {"data":{"helloInDifferentLanguages":["Bonjour","Hola","Zdravstvuyte","Nǐn hǎo","Salve","Gudday","Konnichiwa","Guten Tag"]}} - ``` diff --git a/examples/graphql/basics/pom.xml b/examples/graphql/basics/pom.xml deleted file mode 100644 index cbe70cd4bfb..00000000000 --- a/examples/graphql/basics/pom.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.graphql - helidon-examples-graphql-basics - Helidon Examples GraphQL Basics - - - Basic usage of GraphQL in helidon SE - - - - io.helidon.examples.graphql.basics.Main - - - - - io.helidon.webserver - helidon-webserver-graphql - - - io.helidon.webserver - helidon-webserver - - - io.helidon.common - helidon-common - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - - diff --git a/examples/graphql/basics/src/main/java/io/helidon/examples/graphql/basics/Main.java b/examples/graphql/basics/src/main/java/io/helidon/examples/graphql/basics/Main.java deleted file mode 100644 index 1be76d49915..00000000000 --- a/examples/graphql/basics/src/main/java/io/helidon/examples/graphql/basics/Main.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2020, 2024 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.graphql.basics; - -import java.util.List; - -import io.helidon.webserver.WebServer; -import io.helidon.webserver.graphql.GraphQlService; - -import graphql.schema.DataFetcher; -import graphql.schema.GraphQLSchema; -import graphql.schema.StaticDataFetcher; -import graphql.schema.idl.RuntimeWiring; -import graphql.schema.idl.SchemaGenerator; -import graphql.schema.idl.SchemaParser; -import graphql.schema.idl.TypeDefinitionRegistry; - -/** - * Main class of Graphql SE integration example. - */ -@SuppressWarnings("SpellCheckingInspection") -public class Main { - - private Main() { - } - - /** - * Start the example. Prints endpoints to standard output. - * - * @param args not used - */ - public static void main(String[] args) { - WebServer server = WebServer.builder() - .routing(routing -> routing - .register(GraphQlService.create(buildSchema()))) - .build(); - server.start(); - String endpoint = "http://localhost:" + server.port(); - System.out.printf(""" - GraphQL started on %1$s/graphql - GraphQL schema available on %1$s/graphql/schema.graphql - """, endpoint); - } - - /** - * Generate a {@link GraphQLSchema}. - * - * @return a {@link GraphQLSchema} - */ - private static GraphQLSchema buildSchema() { - String schema = """ - type Query{ - hello: String\s - helloInDifferentLanguages: [String]\s - - }"""; - - SchemaParser schemaParser = new SchemaParser(); - TypeDefinitionRegistry typeDefinitionRegistry = schemaParser.parse(schema); - - // DataFetcher to return various hello's in difference languages - DataFetcher> dataFetcher = environment -> - List.of("Bonjour", "Hola", "Zdravstvuyte", "Nǐn hǎo", "Salve", "Gudday", "Konnichiwa", "Guten Tag"); - - RuntimeWiring runtimeWiring = RuntimeWiring.newRuntimeWiring() - .type("Query", builder -> builder.dataFetcher("hello", new StaticDataFetcher("world"))) - .type("Query", builder -> builder.dataFetcher("helloInDifferentLanguages", dataFetcher)) - .build(); - - SchemaGenerator schemaGenerator = new SchemaGenerator(); - return schemaGenerator.makeExecutableSchema(typeDefinitionRegistry, runtimeWiring); - } -} diff --git a/examples/graphql/basics/src/main/java/io/helidon/examples/graphql/basics/package-info.java b/examples/graphql/basics/src/main/java/io/helidon/examples/graphql/basics/package-info.java deleted file mode 100644 index a0f3c7ceb07..00000000000 --- a/examples/graphql/basics/src/main/java/io/helidon/examples/graphql/basics/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2020, 2021 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 of healthchecks in helidon SE. - */ -package io.helidon.examples.graphql.basics; diff --git a/examples/graphql/pom.xml b/examples/graphql/pom.xml deleted file mode 100644 index ab8d15f8910..00000000000 --- a/examples/graphql/pom.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - 4.0.0 - - helidon-examples-project - io.helidon.examples - 4.1.0-SNAPSHOT - - io.helidon.examples.graphql - helidon-examples-graphql-project - pom - Helidon Examples GraphQL - - - basics - - diff --git a/examples/health/basics/README.md b/examples/health/basics/README.md deleted file mode 100644 index 17c690051fa..00000000000 --- a/examples/health/basics/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Helidon Health Basic Example - -This example shows the basics of using Helidon SE Health. It uses the -set of built-in health checks that Helidon provides plus defines a -custom health check. - -## Build and run - -Start the application: - -```shell -mvn package -java -jar target/helidon-examples-health-basics.jar -``` - -Note the port number reported by the application. - -Probe the health endpoints: - -```shell -curl -i -X GET http://localhost:8080/observe/health/ready -curl -i -X GET http://localhost:8080/observe/health/ -``` diff --git a/examples/health/basics/pom.xml b/examples/health/basics/pom.xml deleted file mode 100644 index 1b67aeb121b..00000000000 --- a/examples/health/basics/pom.xml +++ /dev/null @@ -1,79 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.health - helidon-examples-health-basics - Helidon Examples Health Basics - - - Basic usage of health checks in helidon SE - - - - io.helidon.examples.health.basics.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver.observe - helidon-webserver-observe-health - - - io.helidon.health - helidon-health-checks - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - - diff --git a/examples/health/basics/src/main/java/io/helidon/examples/health/basics/Main.java b/examples/health/basics/src/main/java/io/helidon/examples/health/basics/Main.java deleted file mode 100644 index e3b5ef5d796..00000000000 --- a/examples/health/basics/src/main/java/io/helidon/examples/health/basics/Main.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2018, 2024 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.health.basics; - -import java.time.Duration; - -import io.helidon.health.HealthCheckResponse; -import io.helidon.health.HealthCheckType; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.http.HttpRouting; -import io.helidon.webserver.observe.ObserveFeature; -import io.helidon.webserver.observe.health.HealthObserver; - -/** - * Main class of health check integration example. - */ -public final class Main { - - private static long serverStartTime; - - private Main() { - } - - /** - * Start the example. Prints endpoints to standard output. - * - * @param args not used - */ - public static void main(String[] args) { - serverStartTime = System.currentTimeMillis(); - - // load logging - LogConfig.configureRuntime(); - - ObserveFeature observe = ObserveFeature.builder() - .observersDiscoverServices(true) - .addObserver(HealthObserver.builder() - .details(true) - .useSystemServices(true) - .addCheck(() -> HealthCheckResponse.builder() - .status(HealthCheckResponse.Status.UP) - .detail("time", System.currentTimeMillis()) - .build(), HealthCheckType.READINESS) - .addCheck(() -> HealthCheckResponse.builder() - .status(isStarted()) - .detail("time", System.currentTimeMillis()) - .build(), HealthCheckType.STARTUP) - .build()) - .build(); - - WebServer server = WebServer.builder() - .featuresDiscoverServices(false) - .addFeature(observe) - .routing(Main::routing) - .port(8080) - .build() - .start(); - - System.out.println("WEB server is up! http://localhost:" + server.port()); - } - - /** - * Set up HTTP routing. - * This method is used from tests as well. - * - * @param router HTTP routing builder - */ - static void routing(HttpRouting.Builder router) { - router.get("/hello", (req, res) -> res.send("Hello World!")); - } - - private static boolean isStarted() { - return Duration.ofMillis(System.currentTimeMillis() - serverStartTime).getSeconds() >= 8; - } -} diff --git a/examples/health/basics/src/main/java/io/helidon/examples/health/basics/package-info.java b/examples/health/basics/src/main/java/io/helidon/examples/health/basics/package-info.java deleted file mode 100644 index 52d9f57601a..00000000000 --- a/examples/health/basics/src/main/java/io/helidon/examples/health/basics/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2018, 2021 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 of healthchecks in helidon SE. - */ -package io.helidon.examples.health.basics; diff --git a/examples/health/pom.xml b/examples/health/pom.xml deleted file mode 100644 index 36cc2350fe3..00000000000 --- a/examples/health/pom.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - 4.0.0 - - helidon-examples-project - io.helidon.examples - 4.1.0-SNAPSHOT - - io.helidon.examples.health - helidon-examples-health-project - pom - Helidon Examples Health - - - basics - - diff --git a/examples/integrations/README.md b/examples/integrations/README.md deleted file mode 100644 index 05fd10c9d0c..00000000000 --- a/examples/integrations/README.md +++ /dev/null @@ -1 +0,0 @@ -# Helidon Integrations Examples diff --git a/examples/integrations/cdi/README.md b/examples/integrations/cdi/README.md deleted file mode 100644 index 64fad79554a..00000000000 --- a/examples/integrations/cdi/README.md +++ /dev/null @@ -1 +0,0 @@ -# Helidon Integrations CDI Examples diff --git a/examples/integrations/cdi/datasource-hikaricp-h2/README.md b/examples/integrations/cdi/datasource-hikaricp-h2/README.md deleted file mode 100644 index d630d6a6b87..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp-h2/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# H2 Integration Example - -## Overview - -This example shows a trivial Helidon MicroProfile application that -uses the Hikari connection pool CDI integration and an H2 in-memory -database. - -## Build and run - -```shell -mvn package -java -jar target/helidon-integrations-examples-datasource-hikaricp-h2.jar -``` - -Try the endpoint: -```shell -curl http://localhost:8080/tables -``` diff --git a/examples/integrations/cdi/datasource-hikaricp-h2/pom.xml b/examples/integrations/cdi/datasource-hikaricp-h2/pom.xml deleted file mode 100644 index 44df845d2cd..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp-h2/pom.xml +++ /dev/null @@ -1,103 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../../applications/mp/pom.xml - - io.helidon.examples.integrations.cdi - helidon-integrations-examples-datasource-hikaricp-h2 - Helidon Examples CDI Extensions DataSource/HikariCP H2 - - - - - jakarta.enterprise - jakarta.enterprise.cdi-api - compile - - - jakarta.ws.rs - jakarta.ws.rs-api - compile - - - org.eclipse.microprofile.config - microprofile-config-api - compile - - - - - com.h2database - h2 - runtime - - - io.helidon.integrations.cdi - helidon-integrations-cdi-datasource-hikaricp - runtime - - - io.smallrye - jandex - runtime - true - - - io.helidon.microprofile.server - helidon-microprofile-server - runtime - - - io.helidon.microprofile.config - helidon-microprofile-config - runtime - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/integrations/cdi/datasource-hikaricp-h2/src/main/java/io/helidon/examples/integrations/datasource/hikaricp/jaxrs/TablesResource.java b/examples/integrations/cdi/datasource-hikaricp-h2/src/main/java/io/helidon/examples/integrations/datasource/hikaricp/jaxrs/TablesResource.java deleted file mode 100644 index 35fcaeac4f2..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp-h2/src/main/java/io/helidon/examples/integrations/datasource/hikaricp/jaxrs/TablesResource.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.integrations.datasource.hikaricp.jaxrs; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.Objects; - -import javax.sql.DataSource; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; - -/** - * A JAX-RS resource class in {@linkplain ApplicationScoped - * application scope} rooted at {@code /tables}. - * - * @see #get() - */ -@Path("/tables") -@ApplicationScoped -public class TablesResource { - - private final DataSource dataSource; - - /** - * Creates a new {@link TablesResource}. - * - * @param dataSource the {@link DataSource} to use to acquire - * database table names; must not be {@code null} - * - * @exception NullPointerException if {@code dataSource} is {@code - * null} - */ - @Inject - public TablesResource(@Named("example") final DataSource dataSource) { - super(); - this.dataSource = Objects.requireNonNull(dataSource); - } - - /** - * Returns a {@link Response} which, if successful, contains a - * newline-separated list of Oracle database table names. - * - *

      This method never returns {@code null}.

      - * - * @return a non-{@code null} {@link Response} - * - * @exception SQLException if a database error occurs - */ - @GET - @Produces(MediaType.TEXT_PLAIN) - public Response get() throws SQLException { - final StringBuilder sb = new StringBuilder(); - try (Connection connection = this.dataSource.getConnection(); - PreparedStatement ps = - connection.prepareStatement(" SELECT TABLE_NAME" - + " FROM INFORMATION_SCHEMA.TABLES " - + "ORDER BY TABLE_NAME ASC"); - ResultSet rs = ps.executeQuery()) { - while (rs.next()) { - sb.append(rs.getString(1)).append("\n"); - } - } - final Response returnValue = Response.ok() - .entity(sb.toString()) - .build(); - return returnValue; - } - -} diff --git a/examples/integrations/cdi/datasource-hikaricp-h2/src/main/java/io/helidon/examples/integrations/datasource/hikaricp/jaxrs/package-info.java b/examples/integrations/cdi/datasource-hikaricp-h2/src/main/java/io/helidon/examples/integrations/datasource/hikaricp/jaxrs/package-info.java deleted file mode 100644 index 1dfba973d57..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp-h2/src/main/java/io/helidon/examples/integrations/datasource/hikaricp/jaxrs/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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. - */ - -/** - * Provides JAX-RS-related classes and interfaces for this example - * project. - */ -package io.helidon.examples.integrations.datasource.hikaricp.jaxrs; diff --git a/examples/integrations/cdi/datasource-hikaricp-h2/src/main/resources/META-INF/beans.xml b/examples/integrations/cdi/datasource-hikaricp-h2/src/main/resources/META-INF/beans.xml deleted file mode 100644 index f2f827007a8..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp-h2/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/integrations/cdi/datasource-hikaricp-h2/src/main/resources/META-INF/microprofile-config.properties b/examples/integrations/cdi/datasource-hikaricp-h2/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index f1fd9dc109d..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp-h2/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2019, 2021 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. -# - -# Default database properties. -javax.sql.DataSource.example.dataSourceClassName = org.h2.jdbcx.JdbcDataSource -javax.sql.DataSource.example.dataSource.url = jdbc:h2:mem:sample -javax.sql.DataSource.example.dataSource.user = sa -javax.sql.DataSource.example.dataSource.password = - -# Microprofile server properties -server.port=8080 -server.host=0.0.0.0 diff --git a/examples/integrations/cdi/datasource-hikaricp-mysql/README.md b/examples/integrations/cdi/datasource-hikaricp-mysql/README.md deleted file mode 100644 index 14a20bc6484..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp-mysql/README.md +++ /dev/null @@ -1,60 +0,0 @@ -# MySQL Integration Example - -## Overview - -This example shows a trivial Helidon MicroProfile application that -uses the MySQL CDI integration. It also shows how to run MySQL in a -Docker container and connect to it using the application. - -## Notes - -To run MySQL's `mysql:8` Docker image in a Docker container named -`mysql` that publishes its port 3306 to the host machine's port 3306 -and uses `tiger` as the MySQL root password and that will -automatically be removed when it is stopped: - -```sh -docker container run --rm -d -p 3306:3306 \ - --env MYSQL_ROOT_PASSWORD=tiger \ - --name mysql \ - mysql:8 -``` - -(Note that in the `3306:3306` option value above the first port number -is the port number on the host (i.e. your physical machine running -`docker`) and the second number (after the colon) is the port number -on the Docker container.) - -To ensure that the sample application is configured to talk to MySQL -running in this Docker container, verify that the following lines -(among others) are present in -`src/main/resources/META-INF/microprofile-config.properties`: - -```sh -javax.sql.DataSource.example.dataSourceClassName=com.mysql.cj.jdbc.MysqlDataSource -javax.sql.DataSource.example.dataSource.url = jdbc:mysql://localhost:3306 -javax.sql.DataSource.example.dataSource.user = root -javax.sql.DataSource.example.dataSource.password = tiger -``` - - -## Build and run - -```shell -mvn package -java -jar target/helidon-integrations-examples-datasource-hikaricp-mysql.jar -``` - -Try the endpoint: -```sh -curl http://localhost:8080/tables -``` - -Stop the docker container: -```shell -docker stop mysql -``` - -## References - -- [MySQL Docker documentation](https://hub.docker.com/_/mysql?tab=description) diff --git a/examples/integrations/cdi/datasource-hikaricp-mysql/pom.xml b/examples/integrations/cdi/datasource-hikaricp-mysql/pom.xml deleted file mode 100644 index 4895618df1b..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp-mysql/pom.xml +++ /dev/null @@ -1,104 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../../applications/mp/pom.xml - - io.helidon.examples.integrations.cdi - helidon-integrations-examples-datasource-hikaricp-mysql - Helidon Examples CDI Extensions DataSource/HikariCP MySQL - - - - - jakarta.enterprise - jakarta.enterprise.cdi-api - compile - - - jakarta.ws.rs - jakarta.ws.rs-api - compile - - - org.eclipse.microprofile.config - microprofile-config-api - compile - - - - - com.mysql - mysql-connector-j - runtime - true - - - io.helidon.integrations.cdi - helidon-integrations-cdi-datasource-hikaricp - runtime - - - io.smallrye - jandex - runtime - true - - - io.helidon.microprofile.server - helidon-microprofile-server - runtime - - - io.helidon.microprofile.config - helidon-microprofile-config - runtime - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/integrations/cdi/datasource-hikaricp-mysql/src/main/java/io/helidon/examples/integrations/datasource/hikaricp/jaxrs/TablesResource.java b/examples/integrations/cdi/datasource-hikaricp-mysql/src/main/java/io/helidon/examples/integrations/datasource/hikaricp/jaxrs/TablesResource.java deleted file mode 100644 index 35fcaeac4f2..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp-mysql/src/main/java/io/helidon/examples/integrations/datasource/hikaricp/jaxrs/TablesResource.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.integrations.datasource.hikaricp.jaxrs; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.Objects; - -import javax.sql.DataSource; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; - -/** - * A JAX-RS resource class in {@linkplain ApplicationScoped - * application scope} rooted at {@code /tables}. - * - * @see #get() - */ -@Path("/tables") -@ApplicationScoped -public class TablesResource { - - private final DataSource dataSource; - - /** - * Creates a new {@link TablesResource}. - * - * @param dataSource the {@link DataSource} to use to acquire - * database table names; must not be {@code null} - * - * @exception NullPointerException if {@code dataSource} is {@code - * null} - */ - @Inject - public TablesResource(@Named("example") final DataSource dataSource) { - super(); - this.dataSource = Objects.requireNonNull(dataSource); - } - - /** - * Returns a {@link Response} which, if successful, contains a - * newline-separated list of Oracle database table names. - * - *

      This method never returns {@code null}.

      - * - * @return a non-{@code null} {@link Response} - * - * @exception SQLException if a database error occurs - */ - @GET - @Produces(MediaType.TEXT_PLAIN) - public Response get() throws SQLException { - final StringBuilder sb = new StringBuilder(); - try (Connection connection = this.dataSource.getConnection(); - PreparedStatement ps = - connection.prepareStatement(" SELECT TABLE_NAME" - + " FROM INFORMATION_SCHEMA.TABLES " - + "ORDER BY TABLE_NAME ASC"); - ResultSet rs = ps.executeQuery()) { - while (rs.next()) { - sb.append(rs.getString(1)).append("\n"); - } - } - final Response returnValue = Response.ok() - .entity(sb.toString()) - .build(); - return returnValue; - } - -} diff --git a/examples/integrations/cdi/datasource-hikaricp-mysql/src/main/java/io/helidon/examples/integrations/datasource/hikaricp/jaxrs/package-info.java b/examples/integrations/cdi/datasource-hikaricp-mysql/src/main/java/io/helidon/examples/integrations/datasource/hikaricp/jaxrs/package-info.java deleted file mode 100644 index 1dfba973d57..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp-mysql/src/main/java/io/helidon/examples/integrations/datasource/hikaricp/jaxrs/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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. - */ - -/** - * Provides JAX-RS-related classes and interfaces for this example - * project. - */ -package io.helidon.examples.integrations.datasource.hikaricp.jaxrs; diff --git a/examples/integrations/cdi/datasource-hikaricp-mysql/src/main/resources/META-INF/beans.xml b/examples/integrations/cdi/datasource-hikaricp-mysql/src/main/resources/META-INF/beans.xml deleted file mode 100644 index f2f827007a8..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp-mysql/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/integrations/cdi/datasource-hikaricp-mysql/src/main/resources/META-INF/microprofile-config.properties b/examples/integrations/cdi/datasource-hikaricp-mysql/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 32edc282315..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp-mysql/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2018, 2023 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. -# - -# Default database properties. -javax.sql.DataSource.example.dataSourceClassName=com.mysql.cj.jdbc.MysqlDataSource -javax.sql.DataSource.example.dataSource.url = jdbc:mysql://localhost:3306 -javax.sql.DataSource.example.dataSource.user = root -javax.sql.DataSource.example.dataSource.password = tiger - -# Microprofile server properties -server.port=8080 -server.host=0.0.0.0 diff --git a/examples/integrations/cdi/datasource-hikaricp/.dockerignore b/examples/integrations/cdi/datasource-hikaricp/.dockerignore deleted file mode 100644 index 2f7896d1d13..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -target/ diff --git a/examples/integrations/cdi/datasource-hikaricp/Dockerfile b/examples/integrations/cdi/datasource-hikaricp/Dockerfile deleted file mode 100644 index 5caee647f0f..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp/Dockerfile +++ /dev/null @@ -1,53 +0,0 @@ -# -# Copyright (c) 2018, 2024 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. -# - -# 1st stage, build the app -FROM container-registry.oracle.com/java/jdk-no-fee-term:21 as build - -# Install maven -WORKDIR /usr/share -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 -Dmaven.test.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 container-registry.oracle.com/java/jdk-no-fee-term:21 -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/helidon-examples-integrations-datasource-hikaricp.jar ./ -COPY --from=build /helidon/target/libs ./libs - -CMD [ "java", "-jar", "helidon-examples-integrations-datasource-hikaricp.jar" ] - -EXPOSE 8080 diff --git a/examples/integrations/cdi/datasource-hikaricp/README.md b/examples/integrations/cdi/datasource-hikaricp/README.md deleted file mode 100644 index cb72a0deeaa..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp/README.md +++ /dev/null @@ -1,85 +0,0 @@ -# Hikari Connection Pool Integration Example - -## Overview - -This example shows a trivial Helidon MicroProfile application that -uses the Hikari connection pool CDI integration. It also shows how to -run the Oracle database in a Docker container and connect the -application to it. - -## Prerequisites - -You'll need an Oracle account in order to log in to the Oracle -Container Registry. The Oracle Container Registry is where the Docker -image housing the Oracle database is located. To set up an Oracle -account if you don't already have one, see -[the Oracle account creation website](https://profile.oracle.com/myprofile/account/create-account.jspx). - -## Notes - -To log in to the Oracle Container Registry (which you will need to do -in order to download Oracle database Docker images from it): - -```shell -docker login -u username -p password container-registry.oracle.com -``` - -For more information on the Oracle Container Registry, please visit -its [website](https://container-registry.oracle.com/). - -To run Oracle's `database/standard` Docker image in a Docker container -named `oracle` that publishes ports 1521 and 5500 to -the host while relying on the defaults for all other settings: - -```shell -docker container run -d -it -p 1521:1521 -p 5500:5500 --shm-size=3g \ - --name oracle \ - container-registry.oracle.com/database/standard:latest -``` - -It will take about ten minutes before the database is ready. - -For more information on the Oracle database image used by this -example, you can visit the relevant section of the - [Oracle Container Registry website](https://container-registry.oracle.com/). - -To ensure that the sample application is configured to talk to the -Oracle database running in this Docker container, verify that the -following lines (among others) are present in -`src/main/resources/META-INF/microprofile-config.properties`: - -```properties -javax.sql.DataSource.example.dataSourceClassName=oracle.jdbc.pool.OracleDataSource -javax.sql.DataSource.example.dataSource.url = jdbc:oracle:thin:@localhost:1521:ORCL -javax.sql.DataSource.example.dataSource.user = sys as sysoper -javax.sql.DataSource.example.dataSource.password = Oracle -``` - -## Build and run - -With Docker: -```shell -docker build -t helidon-examples-integrations-datasource-hikaricp . -docker run --rm -d \ - --link oracle \ - -e javax_sql_DataSource_example_dataSource_url="jdbc:oracle:thin:@oracle:1521:ORCL" \ - --name helidon-examples-integrations-datasource-hikaricp \ - -p 8080:8080 helidon-examples-integrations-datasource-hikaricp:latest -``` -OR - -With Maven: -```shell -mvn package -java -jar target/helidon-examples-integrations-datasource-hikaricp.jar -``` - -Try the endpoint: -```shell -curl http://localhost:8080/tables -``` - -Stop the docker containers: -```shell -docker stop oracle helidon-examples-integrations-datasource-hikaricp -``` diff --git a/examples/integrations/cdi/datasource-hikaricp/pom.xml b/examples/integrations/cdi/datasource-hikaricp/pom.xml deleted file mode 100644 index 7c4171d7cd0..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp/pom.xml +++ /dev/null @@ -1,103 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../../applications/mp/pom.xml - - io.helidon.examples.integrations.cdi - helidon-examples-integrations-datasource-hikaricp - Helidon Examples CDI Extensions DataSource/HikariCP - - - - - jakarta.enterprise - jakarta.enterprise.cdi-api - compile - - - jakarta.ws.rs - jakarta.ws.rs-api - compile - - - org.eclipse.microprofile.config - microprofile-config-api - compile - - - - - io.helidon.integrations.db - ojdbc - runtime - - - io.helidon.integrations.cdi - helidon-integrations-cdi-datasource-hikaricp - runtime - - - io.smallrye - jandex - runtime - true - - - io.helidon.microprofile.server - helidon-microprofile-server - runtime - - - io.helidon.microprofile.config - helidon-microprofile-config - runtime - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/integrations/cdi/datasource-hikaricp/src/main/java/io/helidon/examples/integrations/datasource/hikaricp/jaxrs/TablesResource.java b/examples/integrations/cdi/datasource-hikaricp/src/main/java/io/helidon/examples/integrations/datasource/hikaricp/jaxrs/TablesResource.java deleted file mode 100644 index 74026bc5a0c..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp/src/main/java/io/helidon/examples/integrations/datasource/hikaricp/jaxrs/TablesResource.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.integrations.datasource.hikaricp.jaxrs; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.Objects; - -import javax.sql.DataSource; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; - -/** - * A JAX-RS resource class in {@linkplain ApplicationScoped - * application scope} rooted at {@code /tables}. - * - * @see #get() - */ -@Path("/tables") -@ApplicationScoped -public class TablesResource { - - private final DataSource dataSource; - - /** - * Creates a new {@link TablesResource}. - * - * @param dataSource the {@link DataSource} to use to acquire - * database table names; must not be {@code null} - * - * @exception NullPointerException if {@code dataSource} is {@code - * null} - */ - @Inject - public TablesResource(@Named("example") final DataSource dataSource) { - super(); - this.dataSource = Objects.requireNonNull(dataSource); - } - - /** - * Returns a {@link Response} which, if successful, contains a - * newline-separated list of Oracle database table names. - * - *

      This method never returns {@code null}.

      - * - * @return a non-{@code null} {@link Response} - * - * @exception SQLException if a database error occurs - */ - @GET - @Produces(MediaType.TEXT_PLAIN) - public Response get() throws SQLException { - final StringBuilder sb = new StringBuilder(); - try (Connection connection = this.dataSource.getConnection(); - PreparedStatement ps = - connection.prepareStatement(" SELECT TABLE_NAME" - + " FROM ALL_TABLES " - + "ORDER BY TABLE_NAME ASC"); - ResultSet rs = ps.executeQuery()) { - while (rs.next()) { - sb.append(rs.getString(1)).append("\n"); - } - } - final Response returnValue = Response.ok() - .entity(sb.toString()) - .build(); - return returnValue; - } - -} diff --git a/examples/integrations/cdi/datasource-hikaricp/src/main/java/io/helidon/examples/integrations/datasource/hikaricp/jaxrs/package-info.java b/examples/integrations/cdi/datasource-hikaricp/src/main/java/io/helidon/examples/integrations/datasource/hikaricp/jaxrs/package-info.java deleted file mode 100644 index f0ef82d2308..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp/src/main/java/io/helidon/examples/integrations/datasource/hikaricp/jaxrs/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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. - */ - -/** - * Provides JAX-RS-related classes and interfaces for this example - * project. - */ -package io.helidon.examples.integrations.datasource.hikaricp.jaxrs; diff --git a/examples/integrations/cdi/datasource-hikaricp/src/main/resources/META-INF/beans.xml b/examples/integrations/cdi/datasource-hikaricp/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 1b3fbc297cb..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/integrations/cdi/datasource-hikaricp/src/main/resources/META-INF/microprofile-config.properties b/examples/integrations/cdi/datasource-hikaricp/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 1140dcc0511..00000000000 --- a/examples/integrations/cdi/datasource-hikaricp/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,29 +0,0 @@ -# -# Copyright (c) 2018, 2021 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. -# - -# Default database properties. -# See -# https://container-registry.oracle.com/pls/apex/f?p=113:4:102624334361221::NO::: -# and -# https://technology.amis.nl/2017/11/18/run-oracle-database-in-docker-using-prebaked-image-from-oracle-container-registry-a-two-minute-guide/ -javax.sql.DataSource.example.dataSourceClassName=oracle.jdbc.pool.OracleDataSource -javax.sql.DataSource.example.dataSource.url = jdbc:oracle:thin:@localhost:1521:ORCL -javax.sql.DataSource.example.dataSource.user = sys as sysoper -javax.sql.DataSource.example.dataSource.password = Oracle - -# Microprofile server properties -server.port=8080 -server.host=0.0.0.0 diff --git a/examples/integrations/cdi/jpa/README.md b/examples/integrations/cdi/jpa/README.md deleted file mode 100644 index 5a202ed5fd4..00000000000 --- a/examples/integrations/cdi/jpa/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# JPA Integration Example - -With Java: -```shell -mvn package -java -jar target/helidon-integrations-examples-jpa.jar -``` - -Try the endpoint: -```shell -curl -X POST -H "Content-Type: text/plain" http://localhost:8080/foo -d 'bar' -curl http://localhost:8080/foo -``` diff --git a/examples/integrations/cdi/jpa/pom.xml b/examples/integrations/cdi/jpa/pom.xml deleted file mode 100644 index 674456a4a8c..00000000000 --- a/examples/integrations/cdi/jpa/pom.xml +++ /dev/null @@ -1,187 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../../applications/mp/pom.xml - - io.helidon.examples.integrations.cdi - helidon-integrations-examples-jpa - Helidon Examples CDI Extensions JPA - - - - - - jakarta.annotation - jakarta.annotation-api - compile - - - jakarta.enterprise - jakarta.enterprise.cdi-api - compile - - - jakarta.inject - jakarta.inject-api - compile - - - jakarta.ws.rs - jakarta.ws.rs-api - compile - - - jakarta.persistence - jakarta.persistence-api - compile - - - jakarta.transaction - jakarta.transaction-api - compile - - - - - com.h2database - h2 - runtime - - - io.helidon.integrations.cdi - helidon-integrations-cdi-eclipselink - runtime - - - io.helidon.integrations.cdi - helidon-integrations-cdi-jta-weld - runtime - - - io.helidon.integrations.cdi - helidon-integrations-cdi-datasource-hikaricp - runtime - - - io.helidon.integrations.cdi - helidon-integrations-cdi-jpa - runtime - - - io.smallrye - jandex - runtime - true - - - io.helidon.microprofile.server - helidon-microprofile-server - runtime - - - io.helidon.microprofile.config - helidon-microprofile-config - runtime - - - org.eclipse.microprofile.config - microprofile-config-api - runtime - - - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - - - org.hibernate.orm - hibernate-jpamodelgen - ${version.lib.hibernate} - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - org.codehaus.mojo - exec-maven-plugin - - - weave - process-classes - - java - - - org.eclipse.persistence.tools.weaving.jpa.StaticWeave - - -loglevel - INFO - ${project.build.outputDirectory} - ${project.build.outputDirectory} - - - - - - - - diff --git a/examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/Greeting.java b/examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/Greeting.java deleted file mode 100644 index 3ff5bd5e580..00000000000 --- a/examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/Greeting.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2019, 2021 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.integrations.cdi.jpa; - -import java.util.Objects; - -import jakarta.persistence.Access; -import jakarta.persistence.AccessType; -import jakarta.persistence.Basic; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.Table; - -/** - * A contrived representation for example purposes only of a two-part - * greeting as might be stored in a database. - */ -@Access(AccessType.FIELD) -@Entity(name = "Greeting") -@Table(name = "GREETING") -public class Greeting { - - @Id - @Column(name = "FIRSTPART", insertable = true, nullable = false, updatable = false) - private String firstPart; - - @Basic(optional = false) - @Column(name = "SECONDPART", insertable = true, nullable = false, updatable = true) - private String secondPart; - - /** - * Creates a new {@link Greeting}; required by the JPA - * specification and for no other purpose. - * - * @deprecated Please use the {@link #Greeting(String, - * String)} constructor instead. - * - * @see #Greeting(String, String) - */ - @Deprecated - protected Greeting() { - super(); - } - - /** - * Creates a new {@link Greeting}. - * - * @param firstPart the first part of the greeting; must not be - * {@code null} - * - * @param secondPart the second part of the greeting; must not be - * {@code null} - * - * @exception NullPointerException if {@code firstPart} or {@code - * secondPart} is {@code null} - */ - public Greeting(final String firstPart, final String secondPart) { - super(); - this.firstPart = Objects.requireNonNull(firstPart); - this.secondPart = Objects.requireNonNull(secondPart); - } - - /** - * Sets the second part of this greeting. - * - * @param secondPart the second part of this greeting; must not be - * {@code null} - * - * @exception NullPointerException if {@code secondPart} is {@code - * null} - */ - public void setSecondPart(final String secondPart) { - this.secondPart = Objects.requireNonNull(secondPart); - } - - /** - * Returns a {@link String} representation of the second part of - * this {@link Greeting}. - * - *

      This method never returns {@code null}.

      - * - * @return a non-{@code null} {@link String} representation of the - * second part of this {@link Greeting} - */ - @Override - public String toString() { - return this.secondPart; - } - -} diff --git a/examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/HelloWorldApplication.java b/examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/HelloWorldApplication.java deleted file mode 100644 index 790f687ec5d..00000000000 --- a/examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/HelloWorldApplication.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2019, 2021 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.integrations.cdi.jpa; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.ws.rs.core.Application; - -/** - * An example {@link Application} demonstrating the modular - * integration of JPA and JTA with Helidon MicroProfile. - */ -@ApplicationScoped -public class HelloWorldApplication extends Application { - - private final Set> classes; - - /** - * Creates a new {@link HelloWorldApplication}. - */ - public HelloWorldApplication() { - super(); - final Set> classes = new HashSet<>(); - classes.add(HelloWorldResource.class); - classes.add(JPAExceptionMapper.class); - this.classes = Collections.unmodifiableSet(classes); - } - - /** - * Returns a non-{@code null} {@link Set} of {@link Class}es that - * comprise this JAX-RS application. - * - * @return a non-{@code null}, {@linkplain - * Collections#unmodifiableSet(Set) unmodifiable Set} - * - * @see HelloWorldResource - */ - @Override - public Set> getClasses() { - return this.classes; - } - -} diff --git a/examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/HelloWorldResource.java b/examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/HelloWorldResource.java deleted file mode 100644 index ff9f83794d9..00000000000 --- a/examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/HelloWorldResource.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2019, 2021 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.integrations.cdi.jpa; - -import java.net.URI; -import java.util.Objects; - -import jakarta.enterprise.context.RequestScoped; -import jakarta.inject.Inject; -import jakarta.persistence.EntityManager; -import jakarta.persistence.PersistenceContext; -import jakarta.persistence.PersistenceException; -import jakarta.transaction.Status; -import jakarta.transaction.SystemException; -import jakarta.transaction.Transaction; -import jakarta.transaction.Transactional; -import jakarta.transaction.Transactional.TxType; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -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; - -/** - * A JAX-RS root resource class that manipulates greetings in a - * database. - * - * @see #get(String) - * - * @see #post(String, String) - */ -@Path("") -@RequestScoped -public class HelloWorldResource { - - /** - * The {@link EntityManager} used by this class. - * - *

      Note that it behaves as though there is a transaction manager - * in effect, because there is.

      - */ - @PersistenceContext(unitName = "test") - private EntityManager entityManager; - - /** - * A {@link Transaction} that is guaranteed to be non-{@code null} - * only when a transactional method is executing. - * - * @see #post(String, String) - */ - @Inject - private Transaction transaction; - - /** - * Creates a new {@link HelloWorldResource}. - */ - public HelloWorldResource() { - super(); - } - - /** - * Returns a {@link Response} with a status of {@code 404} when - * invoked. - * - * @return a non-{@code null} {@link Response} - */ - @GET - @Path("favicon.ico") - public Response getFavicon() { - return Response.status(404).build(); - } - - /** - * When handed a {@link String} like, say, "{@code hello}", responds - * with the second part of the composite greeting as found via an - * {@link EntityManager}. - * - * @param firstPart the first part of the greeting; must not be - * {@code null} - * - * @return the second part of the greeting; never {@code null} - * - * @exception NullPointerException if {@code firstPart} was {@code - * null} - * - * @exception PersistenceException if the {@link EntityManager} - * encountered an error - */ - @GET - @Path("{firstPart}") - @Produces(MediaType.TEXT_PLAIN) - public String get(@PathParam("firstPart") final String firstPart) { - Objects.requireNonNull(firstPart); - assert this.entityManager != null; - final Greeting greeting = this.entityManager.find(Greeting.class, firstPart); - assert greeting != null; - return greeting.toString(); - } - - /** - * When handed two parts of a greeting, like, say, "{@code hello}" - * and "{@code world}", stores a new {@link Greeting} entity in the - * database appropriately. - * - * @param firstPart the first part of the greeting; must not be - * {@code null} - * - * @param secondPart the second part of the greeting; must not be - * {@code null} - * - * @return the {@link String} representation of the resulting {@link - * Greeting}'s identifier; never {@code null} - * - * @exception NullPointerException if {@code firstPart} or {@code - * secondPart} was {@code null} - * - * @exception PersistenceException if the {@link EntityManager} - * encountered an error - * - * @exception SystemException if something went wrong with the - * transaction - */ - @POST - @Path("{firstPart}") - @Consumes(MediaType.TEXT_PLAIN) - @Produces(MediaType.TEXT_PLAIN) - @Transactional(TxType.REQUIRED) - public Response post(@PathParam("firstPart") final String firstPart, - final String secondPart) - throws SystemException { - Objects.requireNonNull(firstPart); - Objects.requireNonNull(secondPart); - assert this.transaction != null; - assert this.transaction.getStatus() == Status.STATUS_ACTIVE; - assert this.entityManager != null; - assert this.entityManager.isJoinedToTransaction(); - Greeting greeting = this.entityManager.find(Greeting.class, firstPart); - final boolean created; - if (greeting == null) { - greeting = new Greeting(firstPart, secondPart); - this.entityManager.persist(greeting); - created = true; - } else { - greeting.setSecondPart(secondPart); - created = false; - } - assert this.entityManager.contains(greeting); - if (created) { - return Response.created(URI.create(firstPart)).build(); - } else { - return Response.ok(firstPart).build(); - } - } - -} diff --git a/examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/JPAExceptionMapper.java b/examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/JPAExceptionMapper.java deleted file mode 100644 index f9967535f38..00000000000 --- a/examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/JPAExceptionMapper.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2019, 2021 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.integrations.cdi.jpa; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.persistence.EntityNotFoundException; -import jakarta.persistence.NoResultException; -import jakarta.persistence.PersistenceException; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.ext.ExceptionMapper; -import jakarta.ws.rs.ext.Provider; - -/** - * An {@link ExceptionMapper} that handles {@link - * PersistenceException}s. - * - * @see ExceptionMapper - */ -@ApplicationScoped -@Provider -public class JPAExceptionMapper implements ExceptionMapper { - - /** - * Creates a new {@link JPAExceptionMapper}. - */ - public JPAExceptionMapper() { - super(); - } - - /** - * Returns an appropriate non-{@code null} {@link Response} for the - * supplied {@link PersistenceException}. - * - * @param persistenceException the {@link PersistenceException} that - * caused this {@link JPAExceptionMapper} to be invoked; may be - * {@code null} - * - * @return a non-{@code null} {@link Response} representing the - * error - */ - @Override - public Response toResponse(final PersistenceException persistenceException) { - final Response returnValue; - if (persistenceException instanceof NoResultException - || persistenceException instanceof EntityNotFoundException) { - returnValue = Response.status(404).build(); - } else { - returnValue = null; - throw persistenceException; - } - return returnValue; - } - -} diff --git a/examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/package-info.java b/examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/package-info.java deleted file mode 100644 index 7f35d991324..00000000000 --- a/examples/integrations/cdi/jpa/src/main/java/io/helidon/examples/integrations/cdi/jpa/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2019, 2021 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. - */ - -/** - * Provides classes and interfaces demonstrating the usage of JPA and - * JTA integration within Helidon MicroProfile. - */ -package io.helidon.examples.integrations.cdi.jpa; diff --git a/examples/integrations/cdi/jpa/src/main/resources/META-INF/beans.xml b/examples/integrations/cdi/jpa/src/main/resources/META-INF/beans.xml deleted file mode 100644 index f2f827007a8..00000000000 --- a/examples/integrations/cdi/jpa/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/integrations/cdi/jpa/src/main/resources/META-INF/microprofile-config.properties b/examples/integrations/cdi/jpa/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 3c8c1bb7c93..00000000000 --- a/examples/integrations/cdi/jpa/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2019, 2021 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. -# -javax.sql.DataSource.test.dataSourceClassName=org.h2.jdbcx.JdbcDataSource -javax.sql.DataSource.test.dataSource.url=jdbc:h2:mem:test;INIT=CREATE TABLE IF NOT EXISTS GREETING (FIRSTPART VARCHAR NOT NULL, SECONDPART VARCHAR NOT NULL, PRIMARY KEY (FIRSTPART))\\;MERGE INTO GREETING (FIRSTPART, SECONDPART) VALUES ('hello', 'world') -javax.sql.DataSource.test.dataSource.user=sa -javax.sql.DataSource.test.dataSource.password=${EMPTY} - -# Microprofile server properties -server.port=8080 -server.host=0.0.0.0 diff --git a/examples/integrations/cdi/jpa/src/main/resources/META-INF/persistence.xml b/examples/integrations/cdi/jpa/src/main/resources/META-INF/persistence.xml deleted file mode 100644 index 02c6ea5587a..00000000000 --- a/examples/integrations/cdi/jpa/src/main/resources/META-INF/persistence.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - test - io.helidon.examples.integrations.cdi.jpa.Greeting - - - - - - - - - - - - - - - - - - - diff --git a/examples/integrations/cdi/pokemons/README.md b/examples/integrations/cdi/pokemons/README.md deleted file mode 100644 index 132dd40af58..00000000000 --- a/examples/integrations/cdi/pokemons/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# JPA Pokemons Example - -With Java: -```shell -mvn package -java -jar target/helidon-integrations-examples-pokemons.jar -``` - -## Exercise the application - -```shell -curl -X GET http://localhost:8080/pokemon -#Output: [{"id":1,"type":12,"name":"Bulbasaur"}, ...] -``` -```shell -curl -X GET http://localhost:8080/type -#Output: [{"id":1,"name":"Normal"}, ...] -``` -```shell -curl -H "Content-Type: application/json" --request POST --data '{"id":100, "type":1, "name":"Test"}' http://localhost:8080/pokemon -``` - ---- - -Pokémon, and Pokémon character names are trademarks of Nintendo. diff --git a/examples/integrations/cdi/pokemons/pom.xml b/examples/integrations/cdi/pokemons/pom.xml deleted file mode 100644 index 6a67a90fe12..00000000000 --- a/examples/integrations/cdi/pokemons/pom.xml +++ /dev/null @@ -1,185 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../../applications/mp/pom.xml - - io.helidon.examples.integrations.cdi - helidon-integrations-examples-pokemons - Helidon Examples CDI Extensions Pokemons JPA - - - - - jakarta.annotation - jakarta.annotation-api - - - jakarta.enterprise - jakarta.enterprise.cdi-api - - - jakarta.inject - jakarta.inject-api - - - jakarta.ws.rs - jakarta.ws.rs-api - - - jakarta.json.bind - jakarta.json.bind-api - - - jakarta.persistence - jakarta.persistence-api - - - jakarta.transaction - jakarta.transaction-api - - - - - - com.h2database - h2 - runtime - - - io.helidon.integrations.cdi - helidon-integrations-cdi-hibernate - runtime - - - io.helidon.integrations.cdi - helidon-integrations-cdi-jta-weld - runtime - - - io.helidon.integrations.cdi - helidon-integrations-cdi-datasource-hikaricp - runtime - - - io.helidon.integrations.cdi - helidon-integrations-cdi-jpa - runtime - - - io.smallrye - jandex - runtime - true - - - io.helidon.microprofile.server - helidon-microprofile-server - runtime - - - io.helidon.microprofile.metrics - helidon-microprofile-metrics - runtime - - - org.glassfish.jersey.media - jersey-media-json-binding - runtime - - - io.helidon.microprofile.config - helidon-microprofile-config - runtime - - - org.eclipse.microprofile.config - microprofile-config-api - runtime - - - org.hibernate.validator - hibernate-validator-cdi - runtime - - - org.glassfish - jakarta.el - runtime - - - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - org.hibernate.orm.tooling - hibernate-enhance-maven-plugin - - - - true - true - true - - - enhance - - - - - - - diff --git a/examples/integrations/cdi/pokemons/src/main/java/io/helidon/examples/integrations/cdi/pokemon/Pokemon.java b/examples/integrations/cdi/pokemons/src/main/java/io/helidon/examples/integrations/cdi/pokemon/Pokemon.java deleted file mode 100644 index f138be0636c..00000000000 --- a/examples/integrations/cdi/pokemons/src/main/java/io/helidon/examples/integrations/cdi/pokemon/Pokemon.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2020, 2021 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.integrations.cdi.pokemon; - -import jakarta.json.bind.annotation.JsonbTransient; -import jakarta.persistence.Access; -import jakarta.persistence.AccessType; -import jakarta.persistence.Basic; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.NamedQueries; -import jakarta.persistence.NamedQuery; -import jakarta.persistence.Table; -import jakarta.persistence.Transient; - -/** - * A Pokemon entity class. A Pokemon is represented as a triple of an - * ID, a name and a type. - */ -@Entity(name = "Pokemon") -@Table(name = "POKEMON") -@Access(AccessType.PROPERTY) -@NamedQueries({ - @NamedQuery(name = "getPokemons", - query = "SELECT p FROM Pokemon p"), - @NamedQuery(name = "getPokemonByName", - query = "SELECT p FROM Pokemon p WHERE p.name = :name") -}) -public class Pokemon { - - private int id; - - private String name; - - @JsonbTransient - private PokemonType pokemonType; - - private int type; - - /** - * Creates a new pokemon. - */ - public Pokemon() { - } - - @Id - @Column(name = "ID", nullable = false, updatable = false) - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - @Basic(optional = false) - @Column(name = "NAME", nullable = false) - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - /** - * Returns pokemon's type. - * - * @return Pokemon's type. - */ - @ManyToOne - public PokemonType getPokemonType() { - return pokemonType; - } - - /** - * Sets pokemon's type. - * - * @param pokemonType Pokemon's type. - */ - public void setPokemonType(PokemonType pokemonType) { - this.pokemonType = pokemonType; - this.type = pokemonType.getId(); - } - - @Transient - public int getType() { - return type; - } - - public void setType(int type) { - this.type = type; - } -} diff --git a/examples/integrations/cdi/pokemons/src/main/java/io/helidon/examples/integrations/cdi/pokemon/PokemonResource.java b/examples/integrations/cdi/pokemons/src/main/java/io/helidon/examples/integrations/cdi/pokemon/PokemonResource.java deleted file mode 100644 index 7cc9dd29d37..00000000000 --- a/examples/integrations/cdi/pokemons/src/main/java/io/helidon/examples/integrations/cdi/pokemon/PokemonResource.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2020, 2021 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.integrations.cdi.pokemon; - -import java.util.List; - -import jakarta.persistence.EntityManager; -import jakarta.persistence.PersistenceContext; -import jakarta.persistence.TypedQuery; -import jakarta.transaction.Transactional; -import jakarta.ws.rs.BadRequestException; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.NotFoundException; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; - -/** - * This class implements REST endpoints to interact with Pokemons. The following - * operations are supported: - * - * GET /pokemon: Retrieve list of all pokemons - * GET /pokemon/{id}: Retrieve single pokemon by ID - * GET /pokemon/name/{name}: Retrieve single pokemon by name - * DELETE /pokemon/{id}: Delete a pokemon by ID - * POST /pokemon: Create a new pokemon - */ -@Path("pokemon") -public class PokemonResource { - - @PersistenceContext(unitName = "test") - private EntityManager entityManager; - - /** - * Retrieves list of all pokemons. - * - * @return List of pokemons. - */ - @GET - @Produces(MediaType.APPLICATION_JSON) - public List getPokemons() { - return entityManager.createNamedQuery("getPokemons", Pokemon.class).getResultList(); - } - - /** - * Retrieves single pokemon by ID. - * - * @param id The ID. - * @return A pokemon that matches the ID. - * @throws NotFoundException If no pokemon found for the ID. - */ - @GET - @Path("{id}") - @Produces(MediaType.APPLICATION_JSON) - public Pokemon getPokemonById(@PathParam("id") String id) { - try { - return entityManager.find(Pokemon.class, Integer.valueOf(id)); - } catch (IllegalArgumentException e) { - throw new NotFoundException("Unable to find pokemon with ID " + id); - } - } - - /** - * Deletes a single pokemon by ID. - * - * @param id The ID. - */ - @DELETE - @Path("{id}") - @Produces(MediaType.APPLICATION_JSON) - @Transactional(Transactional.TxType.REQUIRED) - public void deletePokemon(@PathParam("id") String id) { - Pokemon pokemon = getPokemonById(id); - entityManager.remove(pokemon); - } - - /** - * Retrieves a pokemon by name. - * - * @param name The name. - * @return A pokemon that matches the name. - * @throws NotFoundException If no pokemon found for the name. - */ - @GET - @Path("name/{name}") - @Produces(MediaType.APPLICATION_JSON) - public Pokemon getPokemonByName(@PathParam("name") String name) { - TypedQuery query = entityManager.createNamedQuery("getPokemonByName", Pokemon.class); - List list = query.setParameter("name", name).getResultList(); - if (list.isEmpty()) { - throw new NotFoundException("Unable to find pokemon with name " + name); - } - return list.get(0); - } - - /** - * Creates a new pokemon. - * - * @param pokemon New pokemon. - * @throws BadRequestException If a problem was found. - */ - @POST - @Consumes(MediaType.APPLICATION_JSON) - @Transactional(Transactional.TxType.REQUIRED) - public void createPokemon(Pokemon pokemon) { - try { - PokemonType pokemonType = entityManager.createNamedQuery("getPokemonTypeById", PokemonType.class) - .setParameter("id", pokemon.getType()).getSingleResult(); - pokemon.setPokemonType(pokemonType); - entityManager.persist(pokemon); - } catch (Exception e) { - throw new BadRequestException("Unable to create pokemon with ID " + pokemon.getId()); - } - } -} - diff --git a/examples/integrations/cdi/pokemons/src/main/java/io/helidon/examples/integrations/cdi/pokemon/PokemonType.java b/examples/integrations/cdi/pokemons/src/main/java/io/helidon/examples/integrations/cdi/pokemon/PokemonType.java deleted file mode 100644 index 664e3a34ea6..00000000000 --- a/examples/integrations/cdi/pokemons/src/main/java/io/helidon/examples/integrations/cdi/pokemon/PokemonType.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2020, 2021 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.integrations.cdi.pokemon; - -import jakarta.persistence.Access; -import jakarta.persistence.AccessType; -import jakarta.persistence.Basic; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.NamedQueries; -import jakarta.persistence.NamedQuery; -import jakarta.persistence.Table; - -/** - * A Pokemon Type entity. A type is represented by an ID and a name. - */ -@Entity(name = "PokemonType") -@Table(name = "POKEMONTYPE") -@Access(AccessType.FIELD) -@NamedQueries({ - @NamedQuery(name = "getPokemonTypes", - query = "SELECT t FROM PokemonType t"), - @NamedQuery(name = "getPokemonTypeById", - query = "SELECT t FROM PokemonType t WHERE t.id = :id") -}) -public class PokemonType { - - @Id - @Column(name = "ID", nullable = false, updatable = false) - private int id; - - @Basic(optional = false) - @Column(name = "NAME") - private String name; - - /** - * Creates a new type. - */ - public PokemonType() { - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } -} diff --git a/examples/integrations/cdi/pokemons/src/main/java/io/helidon/examples/integrations/cdi/pokemon/PokemonTypeResource.java b/examples/integrations/cdi/pokemons/src/main/java/io/helidon/examples/integrations/cdi/pokemon/PokemonTypeResource.java deleted file mode 100644 index 95612879b91..00000000000 --- a/examples/integrations/cdi/pokemons/src/main/java/io/helidon/examples/integrations/cdi/pokemon/PokemonTypeResource.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2020, 2021 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.integrations.cdi.pokemon; - -import java.util.List; - -import jakarta.persistence.EntityManager; -import jakarta.persistence.PersistenceContext; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; - -/** - * This class implements a REST endpoint to retrieve Pokemon types. - * - * GET /type: Retrieve list of all pokemon types - */ -@Path("type") -public class PokemonTypeResource { - - @PersistenceContext(unitName = "test") - private EntityManager entityManager; - - @GET - @Produces(MediaType.APPLICATION_JSON) - public List getPokemonTypes() { - return entityManager.createNamedQuery("getPokemonTypes", PokemonType.class).getResultList(); - } -} diff --git a/examples/integrations/cdi/pokemons/src/main/java/io/helidon/examples/integrations/cdi/pokemon/package-info.java b/examples/integrations/cdi/pokemons/src/main/java/io/helidon/examples/integrations/cdi/pokemon/package-info.java deleted file mode 100644 index c829dc12a11..00000000000 --- a/examples/integrations/cdi/pokemons/src/main/java/io/helidon/examples/integrations/cdi/pokemon/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020 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. - */ - -/** - * Pokemon JPA integration sample. - */ -package io.helidon.examples.integrations.cdi.pokemon; diff --git a/examples/integrations/cdi/pokemons/src/main/resources/META-INF/beans.xml b/examples/integrations/cdi/pokemons/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 4a5ec955fb7..00000000000 --- a/examples/integrations/cdi/pokemons/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/integrations/cdi/pokemons/src/main/resources/META-INF/init_script.sql b/examples/integrations/cdi/pokemons/src/main/resources/META-INF/init_script.sql deleted file mode 100644 index 8d3d00c78ae..00000000000 --- a/examples/integrations/cdi/pokemons/src/main/resources/META-INF/init_script.sql +++ /dev/null @@ -1,25 +0,0 @@ -INSERT INTO POKEMONTYPE VALUES (1, 'Normal'); -INSERT INTO POKEMONTYPE VALUES (2, 'Fighting'); -INSERT INTO POKEMONTYPE VALUES (3, 'Flying'); -INSERT INTO POKEMONTYPE VALUES (4, 'Poison'); -INSERT INTO POKEMONTYPE VALUES (5, 'Ground'); -INSERT INTO POKEMONTYPE VALUES (6, 'Rock'); -INSERT INTO POKEMONTYPE VALUES (7, 'Bug'); -INSERT INTO POKEMONTYPE VALUES (8, 'Ghost'); -INSERT INTO POKEMONTYPE VALUES (9, 'Steel'); -INSERT INTO POKEMONTYPE VALUES (10, 'Fire'); -INSERT INTO POKEMONTYPE VALUES (11, 'Water'); -INSERT INTO POKEMONTYPE VALUES (12, 'Grass'); -INSERT INTO POKEMONTYPE VALUES (13, 'Electric'); -INSERT INTO POKEMONTYPE VALUES (14, 'Psychic'); -INSERT INTO POKEMONTYPE VALUES (15, 'Ice'); -INSERT INTO POKEMONTYPE VALUES (16, 'Dragon'); -INSERT INTO POKEMONTYPE VALUES (17, 'Dark'); -INSERT INTO POKEMONTYPE VALUES (18, 'Fairy'); - -INSERT INTO POKEMON VALUES (1, 'Bulbasaur', 12); -INSERT INTO POKEMON VALUES (2, 'Charmander', 10); -INSERT INTO POKEMON VALUES (3, 'Squirtle', 11); -INSERT INTO POKEMON VALUES (4, 'Caterpie', 7); -INSERT INTO POKEMON VALUES (5, 'Weedle', 7); -INSERT INTO POKEMON VALUES (6, 'Pidgey', 3); diff --git a/examples/integrations/cdi/pokemons/src/main/resources/META-INF/microprofile-config.properties b/examples/integrations/cdi/pokemons/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index c60d395d51c..00000000000 --- a/examples/integrations/cdi/pokemons/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,24 +0,0 @@ -# -# Copyright (c) 2020, 2021 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. -# -javax.sql.DataSource.test.dataSourceClassName=org.h2.jdbcx.JdbcDataSource -#javax.sql.DataSource.test.dataSource.url=jdbc:h2:tcp://localhost:1521/test;IFEXISTS=FALSE -javax.sql.DataSource.test.dataSource.url=jdbc:h2:mem:test;DB_CLOSE_DELAY=-1 -javax.sql.DataSource.test.dataSource.user=sa -javax.sql.DataSource.test.dataSource.password=${EMPTY} - -# Microprofile server properties -server.port=8080 -server.host=0.0.0.0 diff --git a/examples/integrations/cdi/pokemons/src/main/resources/META-INF/persistence.xml b/examples/integrations/cdi/pokemons/src/main/resources/META-INF/persistence.xml deleted file mode 100644 index 6ab3f06f48b..00000000000 --- a/examples/integrations/cdi/pokemons/src/main/resources/META-INF/persistence.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - test - io.helidon.examples.integrations.cdi.pokemon.Pokemon - io.helidon.examples.integrations.cdi.pokemon.PokemonType - - - - - - - - diff --git a/examples/integrations/cdi/pokemons/src/test/java/io/helidon/examples/integrations/cdi/pokemon/MainTest.java b/examples/integrations/cdi/pokemons/src/test/java/io/helidon/examples/integrations/cdi/pokemon/MainTest.java deleted file mode 100644 index 43ee2ebc03f..00000000000 --- a/examples/integrations/cdi/pokemons/src/test/java/io/helidon/examples/integrations/cdi/pokemon/MainTest.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.integrations.cdi.pokemon; - -import io.helidon.microprofile.server.Server; - -import jakarta.enterprise.inject.se.SeContainer; -import jakarta.enterprise.inject.spi.CDI; -import jakarta.json.JsonArray; -import jakarta.ws.rs.client.Client; -import jakarta.ws.rs.client.ClientBuilder; -import jakarta.ws.rs.client.Entity; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - -class MainTest { - - private static Server server; - private static Client client; - - @BeforeAll - public static void startTheServer() { - client = ClientBuilder.newClient(); - server = Server.create().start(); - } - - @AfterAll - static void destroyClass() { - CDI current = CDI.current(); - ((SeContainer) current).close(); - } - - @Test - void testPokemonTypes() { - JsonArray types = client.target(getConnectionString("/type")) - .request() - .get(JsonArray.class); - assertThat(types.size(), is(18)); - } - - @Test - void testPokemon() { - assertThat(getPokemonCount(), is(6)); - - Pokemon pokemon = client.target(getConnectionString("/pokemon/1")) - .request() - .get(Pokemon.class); - assertThat(pokemon.getName(), is("Bulbasaur")); - - pokemon = client.target(getConnectionString("/pokemon/name/Charmander")) - .request() - .get(Pokemon.class); - assertThat(pokemon.getType(), is(10)); - - try (Response response = client.target(getConnectionString("/pokemon/1")) - .request() - .get()) { - assertThat(response.getStatus(), is(200)); - } - - Pokemon test = new Pokemon(); - test.setType(1); - test.setId(100); - test.setName("Test"); - try (Response response = client.target(getConnectionString("/pokemon")) - .request() - .post(Entity.entity(test, MediaType.APPLICATION_JSON))) { - assertThat(response.getStatus(), is(204)); - assertThat(getPokemonCount(), is(7)); - } - - try (Response response = client.target(getConnectionString("/pokemon/100")) - .request() - .delete()) { - assertThat(response.getStatus(), is(204)); - assertThat(getPokemonCount(), is(6)); - } - } - - private int getPokemonCount() { - JsonArray pokemons = client.target(getConnectionString("/pokemon")) - .request() - .get(JsonArray.class); - return pokemons.size(); - } - - private String getConnectionString(String path) { - return "http://localhost:" + server.port() + path; - } -} diff --git a/examples/integrations/cdi/pom.xml b/examples/integrations/cdi/pom.xml deleted file mode 100644 index abbce000c57..00000000000 --- a/examples/integrations/cdi/pom.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - 4.0.0 - - io.helidon.examples.integrations - helidon-examples-integrations-project - 4.1.0-SNAPSHOT - - io.helidon.examples.integrations.cdi - helidon-examples-integrations-cdi-project - pom - Helidon Examples CDI Extensions - - - datasource-hikaricp - datasource-hikaricp-h2 - datasource-hikaricp-mysql - jpa - pokemons - - diff --git a/examples/integrations/micrometer/mp/README.md b/examples/integrations/micrometer/mp/README.md deleted file mode 100644 index 7819c4a0bb3..00000000000 --- a/examples/integrations/micrometer/mp/README.md +++ /dev/null @@ -1,80 +0,0 @@ -# Helidon MP Micrometer Example - -This example shows a simple greeting application, similar to the one from the Helidon MP -QuickStart, but enhanced with Helidon MP Micrometer support to -* time all accesses to the two `GET` endpoints, and - -* count the accesses to the `GET` endpoint which returns a personalized - greeting. - -The example is similar to the one from the Helidon MP QuickStart with these differences: -* The `pom.xml` file contains this additional dependency on the Helidon Micrometer integration - module: -```xml - - io.helidon.integrations - helidon-integrations-micrometer - -``` -* The `GreetingService` includes additional annotations: - * `@Timed` on the two `GET` methods. - * `@Counted` on the `GET` method that returns a personalized greeting. - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-integrations-micrometer-mp.jar -``` - -## Using the app endpoints as with the "classic" greeting app - -These normal greeting app endpoints work just as in the original greeting app: - -```shell -curl -X GET http://localhost:8080/greet -#Output: {"message":"Hello World!"} -``` - -```shell -curl -X GET http://localhost:8080/greet/Joe -#Output: {"message":"Hello Joe!"} -``` - -```shell -curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}' http://localhost:8080/greet/greeting - -curl -X GET http://localhost:8080/greet/Jose -#Output: {"message":"Hola Jose!"} -``` - -## Using Micrometer - -Access the `/micrometer` endpoint which reports the newly-added timer and counter. - -```shell -curl http://localhost:8080/micrometer -``` -Because the `@Timer` annotation specifies a histogram, -the actual timer output includes a lengthy histogram (only part of which is shown below). -Your output might show the `personalizedGets` output before the `allGets` output, -rather than after as shown here. - -```shell -curl http://localhost:8080/micrometer -``` -```listing -# HELP allGets_seconds_max Tracks all GET operations -# TYPE allGets_seconds_max gauge -allGets_seconds_max 0.004840005 -# HELP allGets_seconds Tracks all GET operations -# TYPE allGets_seconds histogram -allGets_seconds_bucket{le="0.001",} 2.0 -allGets_seconds_bucket{le="30.0",} 3.0 -allGets_seconds_bucket{le="+Inf",} 3.0 -allGets_seconds_count 3.0 -allGets_seconds_sum 0.005098119 -# HELP personalizedGets_total Counts personalized GET operations -# TYPE personalizedGets_total counter -personalizedGets_total 2.0 -``` diff --git a/examples/integrations/micrometer/mp/pom.xml b/examples/integrations/micrometer/mp/pom.xml deleted file mode 100644 index 9f90e019622..00000000000 --- a/examples/integrations/micrometer/mp/pom.xml +++ /dev/null @@ -1,107 +0,0 @@ - - - - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../../applications/mp/pom.xml - - 4.0.0 - - Helidon Examples Integration Micrometer MP - - - Basic illustration of Micrometer integration in Helidon MP - - - io.helidon.examples.integrations.micrometer - helidon-examples-integrations-micrometer-mp - - - - io.helidon.microprofile.bundles - helidon-microprofile-core - - - io.helidon.integrations.micrometer - helidon-integrations-micrometer-cdi - - - io.helidon.logging - helidon-logging-jul - runtime - - - org.eclipse.microprofile.openapi - microprofile-openapi-api - - - org.glassfish.jersey.media - jersey-media-json-binding - runtime - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.microprofile.testing - helidon-microprofile-testing-junit5 - test - - - io.helidon.webclient - helidon-webclient - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - - \ No newline at end of file diff --git a/examples/integrations/micrometer/mp/src/main/java/io/helidon/examples/integrations/micrometer/mp/GreetResource.java b/examples/integrations/micrometer/mp/src/main/java/io/helidon/examples/integrations/micrometer/mp/GreetResource.java deleted file mode 100644 index 0714c58da94..00000000000 --- a/examples/integrations/micrometer/mp/src/main/java/io/helidon/examples/integrations/micrometer/mp/GreetResource.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.micrometer.mp; - -import io.micrometer.core.annotation.Counted; -import io.micrometer.core.annotation.Timed; -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 { - - static final String PERSONALIZED_GETS_COUNTER_NAME = "personalizedGets"; - private static final String PERSONALIZED_GETS_COUNTER_DESCRIPTION = "Counts personalized GET operations"; - static final String GETS_TIMER_NAME = "allGets"; - private static final String GETS_TIMER_DESCRIPTION = "Tracks all GET operations"; - - /** - * 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 GreetingMessage} - */ - @GET - @Produces(MediaType.APPLICATION_JSON) - @Timed(value = GETS_TIMER_NAME, description = GETS_TIMER_DESCRIPTION, histogram = true) - public GreetingMessage getDefaultMessage() { - return createResponse("World"); - } - - /** - * Return a greeting message using the name that was provided. - * - * @param name the name to greet - * @return {@link GreetingMessage} - */ - @Path("/{name}") - @GET - @Produces(MediaType.APPLICATION_JSON) - @Counted(value = PERSONALIZED_GETS_COUNTER_NAME, description = PERSONALIZED_GETS_COUNTER_DESCRIPTION) - @Timed(value = GETS_TIMER_NAME, description = GETS_TIMER_DESCRIPTION, histogram = true) - public GreetingMessage getMessage(@PathParam("name") String name) { - return createResponse(name); - } - - /** - * Set the greeting to use in future messages. - * - * @param message {@link GreetingMessage} 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(GreetingMessage message) { - if (message.getMessage() == null) { - GreetingMessage entity = new GreetingMessage("No greeting provided"); - return Response.status(Response.Status.BAD_REQUEST).entity(entity).build(); - } - - greetingProvider.setMessage(message.getMessage()); - return Response.status(Response.Status.NO_CONTENT).build(); - } - - private GreetingMessage createResponse(String who) { - String msg = String.format("%s %s!", greetingProvider.getMessage(), who); - return new GreetingMessage(msg); - } -} diff --git a/examples/integrations/micrometer/mp/src/main/java/io/helidon/examples/integrations/micrometer/mp/GreetingMessage.java b/examples/integrations/micrometer/mp/src/main/java/io/helidon/examples/integrations/micrometer/mp/GreetingMessage.java deleted file mode 100644 index d5e11056131..00000000000 --- a/examples/integrations/micrometer/mp/src/main/java/io/helidon/examples/integrations/micrometer/mp/GreetingMessage.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2023 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.integrations.micrometer.mp; - -/** - * POJO defining the greeting message content. - */ -@SuppressWarnings("unused") -public class GreetingMessage { - private String message; - - /** - * Create a new GreetingMessage instance. - */ - public GreetingMessage() { - } - - /** - * Create a new GreetingMessage instance. - * - * @param message message - */ - public GreetingMessage(String message) { - this.message = message; - } - - /** - * Gets the message value. - * - * @return message value - */ - public String getMessage() { - return message; - } - - /** - * Sets the message value. - * - * @param message message value to set - */ - public void setMessage(String message) { - this.message = message; - } -} diff --git a/examples/integrations/micrometer/mp/src/main/java/io/helidon/examples/integrations/micrometer/mp/GreetingProvider.java b/examples/integrations/micrometer/mp/src/main/java/io/helidon/examples/integrations/micrometer/mp/GreetingProvider.java deleted file mode 100644 index 79d1911407f..00000000000 --- a/examples/integrations/micrometer/mp/src/main/java/io/helidon/examples/integrations/micrometer/mp/GreetingProvider.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2021 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.integrations.micrometer.mp; - -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/integrations/micrometer/mp/src/main/java/io/helidon/examples/integrations/micrometer/mp/package-info.java b/examples/integrations/micrometer/mp/src/main/java/io/helidon/examples/integrations/micrometer/mp/package-info.java deleted file mode 100644 index 01c20ae84cd..00000000000 --- a/examples/integrations/micrometer/mp/src/main/java/io/helidon/examples/integrations/micrometer/mp/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 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 for Micrometer integration. - */ -package io.helidon.examples.integrations.micrometer.mp; diff --git a/examples/integrations/micrometer/mp/src/main/resources/META-INF/beans.xml b/examples/integrations/micrometer/mp/src/main/resources/META-INF/beans.xml deleted file mode 100644 index dbf3e648c1e..00000000000 --- a/examples/integrations/micrometer/mp/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/integrations/micrometer/mp/src/main/resources/META-INF/microprofile-config.properties b/examples/integrations/micrometer/mp/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 91a97c1dccc..00000000000 --- a/examples/integrations/micrometer/mp/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2021 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. -# - -# Application properties. This is the default greeting -app.greeting=Hello - -# Microprofile server properties -server.port=8080 -server.host=0.0.0.0 - -micrometer.builtin-registries.0.type=prometheus -micrometer.builtin-registries.0.prefix=myPrefix diff --git a/examples/integrations/micrometer/mp/src/main/resources/application.yaml b/examples/integrations/micrometer/mp/src/main/resources/application.yaml deleted file mode 100644 index 60a20726fd9..00000000000 --- a/examples/integrations/micrometer/mp/src/main/resources/application.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2021 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. -# - -micrometer: - builtin-registries: - - type: prometheus - prefix: myPrefix \ No newline at end of file diff --git a/examples/integrations/micrometer/mp/src/main/resources/logging.properties b/examples/integrations/micrometer/mp/src/main/resources/logging.properties deleted file mode 100644 index c5299aba06d..00000000000 --- a/examples/integrations/micrometer/mp/src/main/resources/logging.properties +++ /dev/null @@ -1,36 +0,0 @@ -# -# Copyright (c) 2021, 2024 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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.microprofile.level=INFO -#io.helidon.common.level=INFO -#org.glassfish.jersey.level=INFO -#org.jboss.weld=INFO diff --git a/examples/integrations/micrometer/mp/src/test/java/io/helidon/examples/integrations/micrometer/mp/TestEndpoint.java b/examples/integrations/micrometer/mp/src/test/java/io/helidon/examples/integrations/micrometer/mp/TestEndpoint.java deleted file mode 100644 index 284e0d88d89..00000000000 --- a/examples/integrations/micrometer/mp/src/test/java/io/helidon/examples/integrations/micrometer/mp/TestEndpoint.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.micrometer.mp; - -import io.helidon.microprofile.testing.junit5.HelidonTest; - -import io.micrometer.core.instrument.Counter; -import io.micrometer.core.instrument.MeterRegistry; -import jakarta.inject.Inject; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.MediaType; -import org.junit.jupiter.api.Test; - -import static io.helidon.examples.integrations.micrometer.mp.GreetResource.PERSONALIZED_GETS_COUNTER_NAME; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -@HelidonTest -public class TestEndpoint { - - @Inject - private WebTarget webTarget; - - @Inject - private MeterRegistry registry; - - @Test - public void pingGreet() { - - GreetingMessage message = webTarget - .path("/greet/Joe") - .request(MediaType.APPLICATION_JSON_TYPE) - .get(GreetingMessage.class); - - String responseString = message.getMessage(); - - assertThat("Response string", responseString, is("Hello Joe!")); - Counter counter = registry.counter(PERSONALIZED_GETS_COUNTER_NAME); - double before = counter.count(); - - message = webTarget - .path("/greet/Jose") - .request(MediaType.APPLICATION_JSON_TYPE) - .get(GreetingMessage.class); - - responseString = message.getMessage(); - - assertThat("Response string", responseString, is("Hello Jose!")); - double after = counter.count(); - assertThat("Difference in personalized greeting counter between successive calls", after - before, is(1d)); - - } -} diff --git a/examples/integrations/micrometer/pom.xml b/examples/integrations/micrometer/pom.xml deleted file mode 100644 index 1eb8e97ff52..00000000000 --- a/examples/integrations/micrometer/pom.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples.integrations - helidon-examples-integrations-project - 4.1.0-SNAPSHOT - - - helidon-examples-micrometer-project - Helidon Examples Integration Micrometer - - pom - - - se - mp - - - - Basic illustrations of Micrometer integration in Helidon - - - diff --git a/examples/integrations/micrometer/se/README.md b/examples/integrations/micrometer/se/README.md deleted file mode 100644 index 2358b4b55f9..00000000000 --- a/examples/integrations/micrometer/se/README.md +++ /dev/null @@ -1,94 +0,0 @@ -# Helidon SE Micrometer Example - -This example shows a simple greeting application, similar to the one from the -Helidon SE QuickStart, but enhanced with Micrometer support to: - -* time all accesses to the two `GET` endpoints, and - -* count the accesses to the `GET` endpoint which returns a personalized - greeting. - -The Helidon Micrometer integration creates a Micrometer `MeterRegistry` automatically for you. -The `registry()` instance method on `MicrometerSupport` returns that meter registry. - -The `Main` class -1. Uses `MicrometerSupport` to obtain the Micrometer `MeterRegistry` which Helidon SE - automatically provides. - -1. Uses the `MeterRegistry` to: - * Create a Micrometer `Timer` for recording accesses to all `GET` endpoints. - * Create a Micrometer `Counter` for counting accesses to the `GET` endpoint that - returns a personalized greeting. - -1. Registers the built-in support for the `/micrometer` endpoint. - -1. Passes the `Timer` and `Counter` to the `GreetingService` constructor. - -The `GreetingService` class -1. Accepts in the constructor the `Timer` and `Counter` and saves them. -1. Adds routing rules to: - * Update the `Timer` with every `GET` access. - * Increment `Counter` (in addition to returning a personalized greeting) for every - personalized `GET` access. - - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-integrations-micrometer-se.jar -``` - -## Using the app endpoints as with the "classic" greeting app - -These normal greeting app endpoints work just as in the original greeting app: - -```shell -curl -X GET http://localhost:8080/greet -#Output: {"message":"Hello World!"} -``` - -```shell -curl -X GET http://localhost:8080/greet/Joe -#Output: {"message":"Hello Joe!"} -``` - -```shell -curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}' http://localhost:8080/greet/greeting - -curl -X GET http://localhost:8080/greet/Jose -#Output: {"message":"Hola Jose!"} -``` - -## Using Micrometer - -Access the `/micrometer` endpoint which reports the newly-added timer and counter. -```shell -curl http://localhost:8080/micrometer -``` - -Because we created the `Timer` with a histogram, -the actual timer output includes a lengthy histogram (only part of which is shown below). -Your output might show the `personalizedGets` output before the `allGets` output, -rather than after as shown here. - -```shell -curl http://localhost:8080/micrometer -``` -```listing -# HELP allGets_seconds_max -# TYPE allGets_seconds_max gauge -allGets_seconds_max 0.04341847 -# HELP allGets_seconds -# TYPE allGets_seconds histogram -allGets_seconds_bucket{le="0.001",} 0.0 -... -allGets_seconds_bucket{le="30.0",} 3.0 -allGets_seconds_bucket{le="+Inf",} 3.0 -allGets_seconds_count 3.0 -allGets_seconds_sum 0.049222592 -# HELP personalizedGets_total -# TYPE personalizedGets_total counter -personalizedGets_total 2.0 - -``` \ No newline at end of file diff --git a/examples/integrations/micrometer/se/pom.xml b/examples/integrations/micrometer/se/pom.xml deleted file mode 100644 index 8a7f00fb26c..00000000000 --- a/examples/integrations/micrometer/se/pom.xml +++ /dev/null @@ -1,94 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../../applications/se/pom.xml - - - io.helidon.examples.integrations.micrometer-project - helidon-examples-integrations-micrometer-se - - Helidon Examples Integration Micrometer SE - - - Basic illustration of Micrometer integration in Helidon SE - - - - io.helidon.examples.integrations.micrometer.se.Main - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.config - helidon-config-yaml - - - io.helidon.http.media - helidon-http-media-jsonp - - - io.helidon.integrations.micrometer - helidon-integrations-micrometer - - - io.helidon.webclient - helidon-webclient - test - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - diff --git a/examples/integrations/micrometer/se/src/main/java/io/helidon/examples/integrations/micrometer/se/GreetService.java b/examples/integrations/micrometer/se/src/main/java/io/helidon/examples/integrations/micrometer/se/GreetService.java deleted file mode 100644 index 366681f606e..00000000000 --- a/examples/integrations/micrometer/se/src/main/java/io/helidon/examples/integrations/micrometer/se/GreetService.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.micrometer.se; - -import java.util.Collections; - -import io.helidon.config.Config; -import io.helidon.http.Status; -import io.helidon.webserver.http.HttpRequest; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -import io.micrometer.core.instrument.Counter; -import io.micrometer.core.instrument.Timer; -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; - -/** - * A simple service to greet you. - *

      - * Examples: - *

      {@code
      - * 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 greeting message is returned as a JSON object. - * - *

      - */ - -public class GreetService implements HttpService { - - /** - * The config value for the key {@code greeting}. - */ - private String greeting; - - private final Timer getTimer; - private final Counter personalizedGetCounter; - - private static final JsonBuilderFactory JSON_BF = Json.createBuilderFactory(Collections.emptyMap()); - - GreetService(Timer getTimer, Counter personalizedGetCounter) { - Config config = Config.global(); - this.greeting = config.get("app.greeting").asString().orElse("Ciao"); - this.getTimer = getTimer; - this.personalizedGetCounter = personalizedGetCounter; - } - - /** - * A service registers itself by updating the routine rules. - * @param rules the routing rules. - */ - @Override - public void routing(HttpRules rules) { - rules - .get((req, resp) -> getTimer.record(resp::next)) // Update the timer with every GET. - .get("/", this::getDefaultMessageHandler) - .get("/{name}", - (req, resp) -> { - personalizedGetCounter.increment(); - resp.next(); - }, // Count personalized GETs... - this::getMessageHandler) // ...and process them. - .put("/greeting", this::updateGreetingHandler); - } - - /** - * Return a worldly greeting message. - * @param request the server request - * @param response the server response - */ - private void getDefaultMessageHandler(HttpRequest 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().pathParameters().first("name").get(); - sendResponse(response, name); - } - - private void sendResponse(ServerResponse response, String name) { - GreetingMessage msg = new GreetingMessage(String.format("%s %s!", greeting, name)); - response.send(msg.forRest()); - } - - private void updateGreetingFromJson(JsonObject jo, ServerResponse response) { - - if (!jo.containsKey(GreetingMessage.JSON_LABEL)) { - JsonObject jsonErrorObject = JSON_BF.createObjectBuilder() - .add("error", "No greeting provided") - .build(); - response.status(Status.BAD_REQUEST_400) - .send(jsonErrorObject); - return; - } - - greeting = GreetingMessage.fromRest(jo).getMessage(); - response.status(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) { - JsonObject obj = request.content().as(JsonObject.class); - updateGreetingFromJson(obj, response); - } -} diff --git a/examples/integrations/micrometer/se/src/main/java/io/helidon/examples/integrations/micrometer/se/GreetingMessage.java b/examples/integrations/micrometer/se/src/main/java/io/helidon/examples/integrations/micrometer/se/GreetingMessage.java deleted file mode 100644 index f7a71f8203f..00000000000 --- a/examples/integrations/micrometer/se/src/main/java/io/helidon/examples/integrations/micrometer/se/GreetingMessage.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.micrometer.se; - -import java.util.Collections; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import jakarta.json.JsonObjectBuilder; - -/** - * POJO for the greeting message exchanged between the server and the client. - */ -public class GreetingMessage { - - /** - * Label for tagging a {@code GreetingMessage} instance in JSON. - */ - public static final String JSON_LABEL = "greeting"; - - private static final JsonBuilderFactory JSON_BF = Json.createBuilderFactory(Collections.emptyMap()); - - private String message; - - /** - * Create a new greeting with the specified message content. - * - * @param message the message to store in the greeting - */ - public GreetingMessage(String message) { - this.message = message; - } - - /** - * Returns the message value. - * - * @return the message - */ - public String getMessage() { - return message; - } - - /** - * Sets the message value. - * - * @param message value to be set - */ - public void setMessage(String message) { - this.message = message; - } - - /** - * Converts a JSON object (typically read from the request payload) - * into a {@code GreetingMessage}. - * - * @param jsonObject the {@link JsonObject} to convert. - * @return {@code GreetingMessage} set according to the provided object - */ - public static GreetingMessage fromRest(JsonObject jsonObject) { - return new GreetingMessage(jsonObject.getString(JSON_LABEL)); - } - - /** - * Prepares a {@link JsonObject} corresponding to this instance. - * - * @return {@code JsonObject} representing this {@code GreetingMessage} instance - */ - public JsonObject forRest() { - JsonObjectBuilder builder = JSON_BF.createObjectBuilder(); - return builder.add(JSON_LABEL, message) - .build(); - } -} diff --git a/examples/integrations/micrometer/se/src/main/java/io/helidon/examples/integrations/micrometer/se/Main.java b/examples/integrations/micrometer/se/src/main/java/io/helidon/examples/integrations/micrometer/se/Main.java deleted file mode 100644 index bc260a9aa67..00000000000 --- a/examples/integrations/micrometer/se/src/main/java/io/helidon/examples/integrations/micrometer/se/Main.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.micrometer.se; - -import io.helidon.config.Config; -import io.helidon.integrations.micrometer.MicrometerFeature; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.http.HttpRouting; - -import io.micrometer.core.instrument.Counter; -import io.micrometer.core.instrument.Timer; - -/** - * Simple Hello World rest application. - */ -public final class Main { - - static final String PERSONALIZED_GETS_COUNTER_NAME = "personalizedGets"; - static final String ALL_GETS_TIMER_NAME = "allGets"; - - /** - * 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. - */ - static WebServer startServer() { - - // load logging configuration - LogConfig.configureRuntime(); - - // By default, this will pick up application.yaml from the classpath - // and initialize global config - Config config = Config.create(); - Config.global(config); - - WebServer server = WebServer.builder() - .config(config.get("server")) - .routing(Main::setupRouting) - .build() - .start(); - - System.out.println("WEB server is up! http://localhost:" + server.port() + "/greet"); - return server; - } - - /** - * Setup routing. - * - * @param routing routing builder - */ - static void setupRouting(HttpRouting.Builder routing) { - - Config config = Config.global(); - - MicrometerFeature micrometerSupport = MicrometerFeature.create(config); - Counter personalizedGetCounter = micrometerSupport.registry() - .counter(PERSONALIZED_GETS_COUNTER_NAME); - Timer getTimer = Timer.builder(ALL_GETS_TIMER_NAME) - .publishPercentileHistogram() - .register(micrometerSupport.registry()); - - GreetService greetService = new GreetService(getTimer, personalizedGetCounter); - - routing.register("/greet", greetService) - .addFeature(micrometerSupport); - } -} diff --git a/examples/integrations/micrometer/se/src/main/java/io/helidon/examples/integrations/micrometer/se/package-info.java b/examples/integrations/micrometer/se/src/main/java/io/helidon/examples/integrations/micrometer/se/package-info.java deleted file mode 100644 index 26aaa61b34c..00000000000 --- a/examples/integrations/micrometer/se/src/main/java/io/helidon/examples/integrations/micrometer/se/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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 application showing Micrometer support in Helidon SE - *

      - * Start with {@link io.helidon.examples.integrations.micrometer.se.Main} class. - * - * @see io.helidon.examples.integrations.micrometer.se.Main - */ -package io.helidon.examples.integrations.micrometer.se; diff --git a/examples/integrations/micrometer/se/src/main/resources/application.yaml b/examples/integrations/micrometer/se/src/main/resources/application.yaml deleted file mode 100644 index 12336d5f138..00000000000 --- a/examples/integrations/micrometer/se/src/main/resources/application.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# -# Copyright (c) 2021 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. -# - -app: - greeting: "Hello" - -server: - port: 8080 - host: 0.0.0.0 - - diff --git a/examples/integrations/micrometer/se/src/test/java/io/helidon/examples/integrations/micrometer/se/MainTest.java b/examples/integrations/micrometer/se/src/test/java/io/helidon/examples/integrations/micrometer/se/MainTest.java deleted file mode 100644 index 42d2dc60b68..00000000000 --- a/examples/integrations/micrometer/se/src/test/java/io/helidon/examples/integrations/micrometer/se/MainTest.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.micrometer.se; - -import java.util.Collections; - -import io.helidon.config.Config; -import io.helidon.http.Status; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.WebServerConfig.Builder; -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -// we need to first call the methods, before validating metrics -@TestMethodOrder(MethodOrderer.OrderAnnotation.class) -@ServerTest -public class MainTest { - - private static final JsonBuilderFactory JSON_BF = Json.createBuilderFactory(Collections.emptyMap()); - private static final JsonObject TEST_JSON_OBJECT; - - private static double expectedPersonalizedGets; - private static double expectedAllGets; - private final Http1Client client; - - static { - TEST_JSON_OBJECT = JSON_BF.createObjectBuilder() - .add("greeting", "Hola") - .build(); - } - - public MainTest(Http1Client client) { - this.client = client; - } - - @SetUpServer - public static void setup(Builder builder) { - builder.routing(Main::setupRouting); - } - - @Test - @Order(1) - void testDefaultGreeting() { - JsonObject jsonObject = get(); - assertThat(jsonObject.getString("greeting"), is("Hello World!")); - } - - @Test - @Order(2) - void testNamedGreeting() { - JsonObject jsonObject = personalizedGet("Joe"); - Assertions.assertEquals("Hello Joe!", jsonObject.getString("greeting")); - } - - @Test - @Order(3) - void testUpdateGreeting() { - try (Http1ClientResponse response = client.put() - .path("/greet/greeting") - .submit(TEST_JSON_OBJECT)) { - - assertThat(response.status(), is(Status.NO_CONTENT_204)); - } - - JsonObject jsonObject = personalizedGet("Joe"); - assertThat(jsonObject.getString("greeting"), is("Hola Joe!")); - } - - @Test - @Order(4) - void testMicrometer() { - Http1ClientResponse response = client.get() - .path("/micrometer") - .request(); - - assertThat(response.status().code(), is(200)); - - String output = response.as(String.class); - String expected = Main.ALL_GETS_TIMER_NAME + "_seconds_count " + expectedAllGets; - assertThat("Unable to find expected all-gets timer count " + expected + "; output is " + output, - output, containsString(expected)); // all gets; the put - // is not counted - assertThat("Unable to find expected all-gets timer sum", output, - containsString(Main.ALL_GETS_TIMER_NAME + "_seconds_sum")); - expected = Main.PERSONALIZED_GETS_COUNTER_NAME + "_total " + expectedPersonalizedGets; - assertThat("Unable to find expected counter result " + expected + "; output is " + output, - output, containsString(expected)); - response.close(); - } - - private JsonObject get() { - return get("/greet"); - } - - private JsonObject get(String path) { - JsonObject jsonObject = client.get() - .path(path) - .requestEntity(JsonObject.class); - expectedAllGets++; - return jsonObject; - } - - private JsonObject personalizedGet(String name) { - JsonObject result = get("/greet/" + name); - expectedPersonalizedGets++; - return result; - } -} diff --git a/examples/integrations/micronaut/data/README.md b/examples/integrations/micronaut/data/README.md deleted file mode 100644 index 8943e6f49e9..00000000000 --- a/examples/integrations/micronaut/data/README.md +++ /dev/null @@ -1,146 +0,0 @@ -# Helidon Micronaut Data Example - -This example shows integration with Micronaut Data into Helidon MP. - -## Sources - -This example combines Micronaut Data and CDI. - -### CDI classes - -The following classes are CDI and JAX-RS classes that use injected Micronaut beans: - -- `PetResource` - JAX-RS resource exposing Pet REST API -- `OwnerResource` - JAX-RS resource exposing Owner REST API -- `BeanValidationExceptionMapper` - JAX-RS exception mapper to return correct status code - in case of validation failure - -### Micronaut classes - -The following classes are pure Micronaut beans (and cannot have CDI injected into them) - -- `DbPetRepository` - Micronaut Data repository extending an abstract class -- `DbOwnerRepository` - Micronaut Data repository implementing an interface -- `DbPopulateData` - Micronaut startup event listener to initialize the database -- package `model` - data model of the database - -## Build and run - -Start the application: - -```shell -mvn package -java -jar target/helidon-examples-integrations-micronaut-data.jar -``` - -Access endpoints - -```shell -# Get all pets -curl -i http://localhost:8080/pets -# Get all owners -curl -i http://localhost:8080/owners -# Get a single pet -curl -i http://localhost:8080/pets/Dino -# Get a single owner -curl -i http://localhost:8080/owners/Barney -# To fail input validation -curl -i http://localhost:8080/pets/s -``` - -# To use Oracle XE instead of H2 - -- Update ./pom.xml to replace dependency on micronaut-jdbc-hikari with following -``` - - io.micronaut.sql - micronaut-jdbc-ucp - runtime - -``` - -- Update ./pom.xml to replace dependency on com.h2database with following -``` - - io.helidon.integrations.db - ojdbc - runtime - - - com.oracle.database.jdbc - ucp - runtime - -``` - -- Update ./src/main/java/io/helidon/examples/integrations/micronaut/data/DbOwnerRepository.java and - ./src/main/java/io/helidon/examples/integrations/micronaut/data/DbOwnerRepository.java to change from - Dialect.H2 to Dialect.ORACLE - -- Update ./src/main/java/io/helidon/examples/integrations/micronaut/data/DbPopulateData.java to change Typehint to - @TypeHint(typeNames = {"oracle.jdbc.OracleDriver"}) - -- Install Oracle XE - Instructions for running XE in a docker container can be found here: https://github.com/oracle/docker-images/tree/master/OracleDatabase/SingleInstance - -- Update ./src/main/resources/META-INF/microprofile-config.properties to comment out h2 related datasource.* properties and uncomment+update following ones related to XE. -``` -#datasources.default.url=jdbc:oracle:thin:@localhost:/ -#datasources.default.driverClassName=oracle.jdbc.OracleDriver -#datasources.default.username=system -#datasources.default.password= -#datasources.default.schema-generate=CREATE_DROP -#datasources.default.dialect=oracle -``` - -# To use Oracle ATP cloud service instead of H2 - -- Update ./pom.xml to replace dependency on micronaut-jdbc-hikari with following -``` - - io.micronaut.sql - micronaut-jdbc-ucp - runtime - -``` - -- Update ./pom.xml to replace dependency on com.h2database with following -``` - - io.helidon.integrations.db - ojdbc - runtime - - - com.oracle.database.jdbc - ucp - runtime - -``` - -- Update ./src/main/java/io/helidon/examples/integrations/micronaut/data/DbOwnerRepository.java and - ./src/main/java/io/helidon/examples/integrations/micronaut/data/DbOwnerRepository.java to change from - Dialect.H2 to Dialect.ORACLE - -- Update ./src/main/java/io/helidon/examples/integrations/micronaut/data/DbPopulateData.java to change Typehint to - @TypeHint(typeNames = {"oracle.jdbc.OracleDriver"}) - -- Setup ATP - Instructions for ATP setup can be found here: https://blogs.oracle.com/developers/the-complete-guide-to-getting-up-and-running-with-autonomous-database-in-the-cloud - -- Create Schema used by test -``` -CREATE TABLE "PET" ("ID" VARCHAR(36),"OWNER_ID" NUMBER(19) NOT NULL,"NAME" VARCHAR(255) NOT NULL,"TYPE" VARCHAR(255) NOT NULL); -CREATE SEQUENCE "OWNER_SEQ" MINVALUE 1 START WITH 1 NOCACHE NOCYCLE; -CREATE TABLE "OWNER" ("ID" NUMBER(19) PRIMARY KEY NOT NULL,"AGE" NUMBER(10) NOT NULL,"NAME" VARCHAR(255) NOT NULL); -``` - -- Update ./src/main/resources/META-INF/microprofile-config.properties to comment out h2 related datasource.* properties and add uncomment+update following ones related to ATP. -``` -#datasources.default.url=jdbc:oracle:thin:@?TNS_ADMIN= -#datasources.default.driverClassName=oracle.jdbc.OracleDriver -#datasources.default.username= -#datasources.default.password= -#datasources.default.schema-generate=NONE -#datasources.default.dialect=oracle -``` \ No newline at end of file diff --git a/examples/integrations/micronaut/data/pom.xml b/examples/integrations/micronaut/data/pom.xml deleted file mode 100644 index 443dd344205..00000000000 --- a/examples/integrations/micronaut/data/pom.xml +++ /dev/null @@ -1,157 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../../applications/mp/pom.xml - - helidon-examples-integrations-micronaut-data - Helidon Examples Integration Micronaut Data - - - - jakarta.persistence - jakarta.persistence-api - provided - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.micronaut.data - micronaut-data-jdbc - - - io.micronaut - micronaut-runtime - - - io.helidon.integrations.micronaut - helidon-integrations-micronaut-cdi - runtime - - - io.helidon.integrations.micronaut - helidon-integrations-micronaut-data - runtime - - - io.micronaut.data - micronaut-data-tx - runtime - - - io.micronaut.sql - micronaut-jdbc-hikari - runtime - - - com.h2database - - - h2 - runtime - - - io.smallrye - jandex - runtime - true - - - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.microprofile.testing - helidon-microprofile-testing-junit5 - test - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - true - - - io.micronaut - micronaut-inject-java - ${version.lib.micronaut} - - - io.micronaut - micronaut-validation - ${version.lib.micronaut} - - - io.micronaut.data - micronaut-data-processor - ${version.lib.micronaut.data} - - - io.helidon.integrations.micronaut - helidon-integrations-micronaut-cdi-processor - ${helidon.version} - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/BeanValidationExceptionMapper.java b/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/BeanValidationExceptionMapper.java deleted file mode 100644 index ca2f919979a..00000000000 --- a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/BeanValidationExceptionMapper.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.integrations.micronaut.data; - -import javax.validation.ConstraintViolationException; - -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.ext.ExceptionMapper; -import jakarta.ws.rs.ext.Provider; - -/** - * A JAX-RS provider that maps {@link jakarta.validation.ConstraintViolationException} from bean validation - * to a proper JAX-RS response with {@link jakarta.ws.rs.core.Response.Status#BAD_REQUEST} status. - * If this provider is not present, validation exception from Micronaut would end with an internal server - * error. - */ -@Provider -public class BeanValidationExceptionMapper implements ExceptionMapper { - @Override - public Response toResponse(ConstraintViolationException exception) { - return Response.status(Response.Status.BAD_REQUEST) - .entity(exception.getMessage()) - .build(); - } -} diff --git a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/DbOwnerRepository.java b/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/DbOwnerRepository.java deleted file mode 100644 index f2fc239475c..00000000000 --- a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/DbOwnerRepository.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2020 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.integrations.micronaut.data; - -import java.util.List; -import java.util.Optional; - -import io.helidon.examples.integrations.micronaut.data.model.Owner; - -import io.micronaut.data.jdbc.annotation.JdbcRepository; -import io.micronaut.data.model.query.builder.sql.Dialect; -import io.micronaut.data.repository.CrudRepository; - -/** - * Micronaut Data repository for pet owners. - */ -@JdbcRepository(dialect = Dialect.H2) -public interface DbOwnerRepository extends CrudRepository { - /** - * Get all owners from the database. - * - * @return all owners - */ - @Override - List findAll(); - - /** - * Find an owner by name. - * - * @param name name of owner - * @return owner if found - */ - Optional findByName(String name); -} diff --git a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/DbPetRepository.java b/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/DbPetRepository.java deleted file mode 100644 index 0763abc32ca..00000000000 --- a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/DbPetRepository.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2020 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.integrations.micronaut.data; - -import java.util.List; -import java.util.Optional; -import java.util.UUID; - -import io.helidon.examples.integrations.micronaut.data.model.NameDTO; -import io.helidon.examples.integrations.micronaut.data.model.Pet; - -import io.micronaut.data.annotation.Join; -import io.micronaut.data.jdbc.annotation.JdbcRepository; -import io.micronaut.data.model.Pageable; -import io.micronaut.data.model.query.builder.sql.Dialect; -import io.micronaut.data.repository.PageableRepository; - -/** - * Micronaut data repository for pets. - */ -@JdbcRepository(dialect = Dialect.H2) -public abstract class DbPetRepository implements PageableRepository { - - /** - * Get all pets. - * - * @param pageable pageable instance - * @return list of pets - */ - public abstract List list(Pageable pageable); - - /** - * Find a pet by its name. - * - * @param name pet name - * @return pet if it was found - */ - @Join("owner") - public abstract Optional findByName(String name); -} diff --git a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/DbPopulateData.java b/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/DbPopulateData.java deleted file mode 100644 index 9ff63da26aa..00000000000 --- a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/DbPopulateData.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2020, 2021 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. - */ -/* - This class is almost exactly copied from Micronaut examples. - */ -package io.helidon.examples.integrations.micronaut.data; - -import java.util.Arrays; - -import io.helidon.examples.integrations.micronaut.data.model.Owner; -import io.helidon.examples.integrations.micronaut.data.model.Pet; - -import io.micronaut.context.event.StartupEvent; -import io.micronaut.core.annotation.TypeHint; -import io.micronaut.runtime.event.annotation.EventListener; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; - -/** - * A Micronaut bean that listens on startup event and populates database with data. - */ -@Singleton -@TypeHint(typeNames = {"org.h2.Driver", "org.h2.mvstore.db.MVTableEngine"}) -public class DbPopulateData { - private final DbOwnerRepository ownerRepository; - private final DbPetRepository petRepository; - - @Inject - DbPopulateData(DbOwnerRepository ownerRepository, DbPetRepository petRepository) { - this.ownerRepository = ownerRepository; - this.petRepository = petRepository; - } - - @EventListener - void init(StartupEvent event) { - Owner fred = new Owner("Fred"); - fred.setAge(45); - Owner barney = new Owner("Barney"); - barney.setAge(40); - ownerRepository.saveAll(Arrays.asList(fred, barney)); - - Pet dino = new Pet("Dino", fred); - Pet bp = new Pet("Baby Puss", fred); - bp.setType(Pet.PetType.CAT); - Pet hoppy = new Pet("Hoppy", barney); - - petRepository.saveAll(Arrays.asList(dino, bp, hoppy)); - } -} diff --git a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/OwnerResource.java b/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/OwnerResource.java deleted file mode 100644 index b4032aa005e..00000000000 --- a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/OwnerResource.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.integrations.micronaut.data; - -import io.helidon.examples.integrations.micronaut.data.model.Owner; - -import jakarta.inject.Inject; -import jakarta.validation.constraints.Pattern; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.NotFoundException; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import org.eclipse.microprofile.metrics.annotation.Timed; - -/** - * JAX-RS resource, and the MicroProfile entry point to manage pet owners. - * This resource used Micronaut data beans (repositories) to query database, and - * bean validation as implemented by Micronaut. - */ -@Path("/owners") -public class OwnerResource { - private final DbOwnerRepository ownerRepository; - - /** - * Create a new instance with repository. - * - * @param ownerRepo owner repository from Micronaut data - */ - @Inject - public OwnerResource(DbOwnerRepository ownerRepo) { - this.ownerRepository = ownerRepo; - } - - /** - * Gets all owners from the database. - * @return all owners, using JSON-B to map them to JSON - */ - @GET - public Iterable getAll() { - return ownerRepository.findAll(); - } - - /** - * Get a named owner from the database. - * - * @param name name of the owner to find, must be at least two characters long, may contain whitespace - * @return a single owner - * @throws jakarta.ws.rs.NotFoundException in case the owner is not in the database (to return 404 status) - */ - @Path("/{name}") - @GET - @Timed - public Owner owner(@PathParam("name") @Pattern(regexp = "\\w+[\\w+\\s?]*\\w") String name) { - return ownerRepository.findByName(name) - .orElseThrow(() -> new NotFoundException("Owner by name " + name + " does not exist")); - } -} diff --git a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/PetResource.java b/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/PetResource.java deleted file mode 100644 index 87bc2391b4a..00000000000 --- a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/PetResource.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.integrations.micronaut.data; - -import javax.validation.constraints.Pattern; - -import io.helidon.examples.integrations.micronaut.data.model.Pet; - -import jakarta.inject.Inject; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.NotFoundException; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import org.eclipse.microprofile.metrics.annotation.Timed; - -/** - * JAX-RS resource, and the MicroProfile entry point to manage pets. - * This resource used Micronaut data beans (repositories) to query database, and - * bean validation as implemented by Micronaut. - */ -@Path("/pets") -public class PetResource { - private final DbPetRepository petRepository; - - /** - * Create a new instance with pet repository. - * - * @param petRepo Pet repository from Micronaut data - */ - @Inject - public PetResource(DbPetRepository petRepo) { - this.petRepository = petRepo; - } - - /** - * Gets all pets from the database. - * @return all pets, using JSON-B to map them to JSON - */ - @GET - public Iterable getAll() { - return petRepository.findAll(); - } - - /** - * Get a named pet from the database. - * - * @param name name of the pet to find, must be at least two characters long, may contain whitespace - * @return a single pet - * @throws jakarta.ws.rs.NotFoundException in case the pet is not in the database (to return 404 status) - */ - @Path("/{name}") - @GET - @Timed - public Pet pet(@PathParam("name") @Pattern(regexp = "\\w+[\\w+\\s?]*\\w") String name) { - return petRepository.findByName(name) - .orElseThrow(() -> new NotFoundException("Pet by name " + name + " does not exist")); - } -} diff --git a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/NameDTO.java b/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/NameDTO.java deleted file mode 100644 index 1b299545c2d..00000000000 --- a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/NameDTO.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2020 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.integrations.micronaut.data.model; - -import io.micronaut.core.annotation.Introspected; - -/** - * Used in list of names of pets. - */ -@Introspected -public class NameDTO { - private String name; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } -} diff --git a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/Owner.java b/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/Owner.java deleted file mode 100644 index 63cdcbe423b..00000000000 --- a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/Owner.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2020, 2021 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.integrations.micronaut.data.model; - -import io.micronaut.core.annotation.Creator; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; - -/** - * Owner database entity. - */ -@Entity -public class Owner { - - @Id - @GeneratedValue - private Long id; - private String name; - private int age; - - /** - * Create a named owner. - * - * @param name name of the owner - */ - @Creator - public Owner(String name) { - this.name = name; - } - - public int getAge() { - return age; - } - - public void setAge(int age) { - this.age = age; - } - - public String getName() { - return name; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - -} diff --git a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/Pet.java b/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/Pet.java deleted file mode 100644 index 25e1ec00551..00000000000 --- a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/Pet.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2020, 2021 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.integrations.micronaut.data.model; - -import java.util.UUID; - -import io.micronaut.core.annotation.Creator; -import io.micronaut.core.annotation.Nullable; -import io.micronaut.data.annotation.AutoPopulated; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.ManyToOne; - -/** - * Pet database entity. - */ -@Entity -public class Pet { - - @Id - @AutoPopulated - private UUID id; - private String name; - @ManyToOne - private Owner owner; - private PetType type = PetType.DOG; - - /** - * Creates a new pet. - * @param name name of the pet - * @param owner owner of the pet (optional) - */ - // NOTE - please use Nullable from this package, jakarta.annotation.Nullable will fail with JPMS, - // as it is declared in the same package as is used by annother module (jakarta.annotation-api) - @Creator - public Pet(String name, @Nullable Owner owner) { - this.name = name; - this.owner = owner; - } - - public Owner getOwner() { - return owner; - } - - public String getName() { - return name; - } - - public UUID getId() { - return id; - } - - public PetType getType() { - return type; - } - - public void setType(PetType type) { - this.type = type; - } - - public void setId(UUID id) { - this.id = id; - } - - /** - * Type of pet. - */ - public enum PetType { - /** - * Dog. - */ - DOG, - /** - * Cat. - */ - CAT - } -} diff --git a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/package-info.java b/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/package-info.java deleted file mode 100644 index 054b464733d..00000000000 --- a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/model/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020 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. - */ - -/** - * Model classes for entities and transfer objects. - */ -package io.helidon.examples.integrations.micronaut.data.model; diff --git a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/package-info.java b/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/package-info.java deleted file mode 100644 index 94bf5dc2f9c..00000000000 --- a/examples/integrations/micronaut/data/src/main/java/io/helidon/examples/integrations/micronaut/data/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020 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 showing use of Micronaut Data in Helidon MicroProfile server. - */ -package io.helidon.examples.integrations.micronaut.data; diff --git a/examples/integrations/micronaut/data/src/main/resources/META-INF/beans.xml b/examples/integrations/micronaut/data/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 4a5ec955fb7..00000000000 --- a/examples/integrations/micronaut/data/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/integrations/micronaut/data/src/main/resources/META-INF/microprofile-config.properties b/examples/integrations/micronaut/data/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 7e187711976..00000000000 --- a/examples/integrations/micronaut/data/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,40 +0,0 @@ -# -# Copyright (c) 2020, 2021 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 - -#When native image is used, we must use remote h2 -#datasources.default.url=jdbc:h2:tcp://localhost:9092/test -datasources.default.url=jdbc:h2:mem:devDb;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE -datasources.default.driverClassName=org.h2.Driver -datasources.default.username=sa -datasources.default.password=${EMPTY} -datasources.default.schema-generate=CREATE_DROP -datasources.default.dialect=h2 - -#datasources.default.url=jdbc:oracle:thin:@localhost:/ -#datasources.default.driverClassName=oracle.jdbc.OracleDriver -#datasources.default.username=system -#datasources.default.password= -#datasources.default.schema-generate=CREATE_DROP -#datasources.default.dialect=oracle - -#datasources.default.url=jdbc:oracle:thin:@?TNS_ADMIN= -#datasources.default.driverClassName=oracle.jdbc.OracleDriver -#datasources.default.username= -#datasources.default.password= -#datasources.default.schema-generate=NONE -#datasources.default.dialect=oracle diff --git a/examples/integrations/micronaut/data/src/main/resources/logging.properties b/examples/integrations/micronaut/data/src/main/resources/logging.properties deleted file mode 100644 index 42482e19bd9..00000000000 --- a/examples/integrations/micronaut/data/src/main/resources/logging.properties +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2020, 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. -# - -# Send messages to the console -handlers=io.helidon.logging.jul.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 - -io.helidon.level=INFO diff --git a/examples/integrations/micronaut/data/src/test/java/io/helidon/examples/integrations/micronaut/data/MicronautExampleTest.java b/examples/integrations/micronaut/data/src/test/java/io/helidon/examples/integrations/micronaut/data/MicronautExampleTest.java deleted file mode 100644 index 40681eae743..00000000000 --- a/examples/integrations/micronaut/data/src/test/java/io/helidon/examples/integrations/micronaut/data/MicronautExampleTest.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.integrations.micronaut.data; - -import io.helidon.examples.integrations.micronaut.data.model.Pet; -import io.helidon.microprofile.testing.junit5.HelidonTest; - -import jakarta.inject.Inject; -import jakarta.json.JsonArray; -import jakarta.json.JsonObject; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.Response; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -@HelidonTest -class MicronautExampleTest { - @Inject - private WebTarget webTarget; - - @Test - void testAllPets() { - JsonArray jsonValues = webTarget.path("/pets") - .request() - .get(JsonArray.class); - - assertThat("We should get all pets", jsonValues.size(), is(3)); - } - - @Test - void testGetPet() { - JsonObject pet = webTarget.path("/pets/Dino") - .request() - .get(JsonObject.class); - - assertThat(pet.getString("name"), is("Dino")); - assertThat(pet.getString("type"), is(Pet.PetType.DOG.toString())); - } - - @Test - void testNotFound() { - try (Response response = webTarget.path("/pets/Fino") - .request() - .get()) { - assertThat("Should be not found: 404", response.getStatus(), is(404)); - } - } - - @Test - void testValidationError() { - try (Response response = webTarget.path("/pets/a") - .request() - .get()) { - assertThat("Should be bad request: 400", response.getStatus(), is(400)); - } - } - -} \ No newline at end of file diff --git a/examples/integrations/micronaut/pom.xml b/examples/integrations/micronaut/pom.xml deleted file mode 100644 index 807a130ea0d..00000000000 --- a/examples/integrations/micronaut/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - 4.0.0 - - io.helidon.examples.integrations - helidon-examples-integrations-project - 4.1.0-SNAPSHOT - - io.helidon.examples.integrations.micronaut - helidon-examples-integrations-micronaut-project - pom - Helidon Examples Integration Micronaut - - - data - - diff --git a/examples/integrations/microstream/README.md b/examples/integrations/microstream/README.md deleted file mode 100644 index d48be20727c..00000000000 --- a/examples/integrations/microstream/README.md +++ /dev/null @@ -1 +0,0 @@ -# Microstream Integrations Examples diff --git a/examples/integrations/microstream/greetings-mp/README.md b/examples/integrations/microstream/greetings-mp/README.md deleted file mode 100644 index b298250df2e..00000000000 --- a/examples/integrations/microstream/greetings-mp/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# Microstream integration example - -This example uses Microstream to persist the greetings supplied - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-integrations-microstream-greetings-mp.jar -``` - -## Endpoints - -Get default greeting message: -```shell -curl -X GET http://localhost:7001/greet -``` - -Get greeting message for Joe: - -```shell -curl -X GET http://localhost:7001/greet/Joe -``` - -Add a greeting: -```shell -curl -X PUT -H "Content-Type: application/json" -d '{"message" : "Howdy"}' http://localhost:7001/greet/greeting -``` \ No newline at end of file diff --git a/examples/integrations/microstream/greetings-mp/pom.xml b/examples/integrations/microstream/greetings-mp/pom.xml deleted file mode 100644 index 41f9b477a75..00000000000 --- a/examples/integrations/microstream/greetings-mp/pom.xml +++ /dev/null @@ -1,84 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../../applications/mp/pom.xml - - - helidon-examples-integrations-microstream-greetings-mp - Helidon Examples Integration Microstream Greetings mp - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.integrations.microstream - helidon-integrations-microstream-cdi - - - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.microprofile.testing - helidon-microprofile-testing-junit5 - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - - \ No newline at end of file diff --git a/examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/GreetResource.java b/examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/GreetResource.java deleted file mode 100644 index 314f2df567a..00000000000 --- a/examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/GreetResource.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.microstream.greetings.mp; - -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; - -/** - * A simple service to greet you. Examples: - * - * Get default greeting message: - * curl -X GET http://localhost:7001/greet - * - * Get greeting message for Joe: - * curl -X GET http://localhost:7001/greet/Joe - * - * add a greeting - * curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Howdy"}' http://localhost:7001/greet/greeting - * - * The message is returned as a JSON object - */ -@Path("/greet") -@RequestScoped -public class GreetResource { - - 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 default greeting message. - * - * @return {@link GreetingMessage} - */ - @GET - @Produces(MediaType.APPLICATION_JSON) - public GreetingMessage getDefaultMessage() { - return createResponse("World"); - } - - private GreetingMessage createResponse(String who) { - String msg = String.format("%s %s!", greetingProvider.getGreeting(), who); - - return new GreetingMessage(msg); - } - - /** - * Return a greeting message using the name that was provided. - * - * @param name the name to greet - * @return {@link GreetingMessage} - */ - @Path("/{name}") - @GET - @Produces(MediaType.APPLICATION_JSON) - public GreetingMessage getMessage(@PathParam("name") String name) { - return createResponse(name); - } - - /** - * Set the greeting to use in future messages. - * - * @param message JSON containing the new greeting - * @return {@link Response} - */ - @Path("/greeting") - @PUT - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - public Response updateGreeting(GreetingMessage message) { - if (message.getMessage() == null) { - GreetingMessage entity = new GreetingMessage("No greeting provided"); - return Response.status(Response.Status.BAD_REQUEST).entity(entity).build(); - } - - greetingProvider.addGreeting(message.getMessage()); - return Response.status(Response.Status.NO_CONTENT).build(); - } - -} diff --git a/examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/GreetingMessage.java b/examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/GreetingMessage.java deleted file mode 100644 index e57afc8b6d6..00000000000 --- a/examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/GreetingMessage.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2023 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.integrations.microstream.greetings.mp; - -/** - * POJO defining the greeting message content. - */ -@SuppressWarnings("unused") -public class GreetingMessage { - private String message; - - /** - * Create a new GreetingMessage instance. - */ - public GreetingMessage() { - } - - /** - * Create a new GreetingMessage instance. - * - * @param message message - */ - public GreetingMessage(String message) { - this.message = message; - } - - /** - * Gets the message value. - * - * @return message value - */ - public String getMessage() { - return message; - } - - /** - * Sets the message value. - * - * @param message message value to set - */ - public void setMessage(String message) { - this.message = message; - } -} diff --git a/examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/GreetingProvider.java b/examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/GreetingProvider.java deleted file mode 100644 index f4c6446ab5c..00000000000 --- a/examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/GreetingProvider.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2021 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.integrations.microstream.greetings.mp; - -import java.util.ArrayList; -import java.util.List; -import java.util.Random; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import io.helidon.integrations.microstream.cdi.MicrostreamStorage; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import one.microstream.storage.embedded.types.EmbeddedStorageManager; - -/** - * Provider for greeting message that are persisted by microstream. - */ -@ApplicationScoped -public class GreetingProvider { - - private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true); - private final EmbeddedStorageManager storage; - private final Random rnd = new Random(); - - private List greetingMessages; - - /** - * Creates new GreetingProvider using a microstream EmbeddedStorageManager. - * - * @param storage the used EmbeddedStorageManager. - */ - @SuppressWarnings("unchecked") - @Inject - public GreetingProvider(@MicrostreamStorage(configNode = "one.microstream.storage.greetings") - EmbeddedStorageManager storage) { - super(); - this.storage = storage; - - // load stored data - greetingMessages = (List) storage.root(); - - // Initialize storage if empty - if (greetingMessages == null) { - greetingMessages = new ArrayList<>(); - storage.setRoot(greetingMessages); - storage.storeRoot(); - addGreeting("Hello"); - } - } - - /** - * Add a new greeting to the available greetings and persist it. - * - * @param newGreeting the new greeting to be added and persisted. - */ - public void addGreeting(String newGreeting) { - try { - lock.writeLock().lock(); - greetingMessages.add(newGreeting); - storage.store(greetingMessages); - } finally { - lock.writeLock().unlock(); - } - } - - /** - * returns a random greeting. - * - * @return a greeting. - */ - public String getGreeting() { - try { - lock.readLock().lock(); - return greetingMessages.get(rnd.nextInt(greetingMessages.size())); - } finally { - lock.readLock().unlock(); - } - } - -} diff --git a/examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/package-info.java b/examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/package-info.java deleted file mode 100644 index 01a14d7ff31..00000000000 --- a/examples/integrations/microstream/greetings-mp/src/main/java/io/helidon/examples/integrations/microstream/greetings/mp/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 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. - */ - -/** - * An example that uses Microstream to persist the greetings. - */ -package io.helidon.examples.integrations.microstream.greetings.mp; diff --git a/examples/integrations/microstream/greetings-mp/src/main/resources/META-INF/beans.xml b/examples/integrations/microstream/greetings-mp/src/main/resources/META-INF/beans.xml deleted file mode 100644 index dbf3e648c1e..00000000000 --- a/examples/integrations/microstream/greetings-mp/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/integrations/microstream/greetings-mp/src/main/resources/META-INF/microprofile-config.properties b/examples/integrations/microstream/greetings-mp/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 1f72e871dda..00000000000 --- a/examples/integrations/microstream/greetings-mp/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2019, 2023 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. -# - -one.microstream.storage.greetings.storage-directory=./greetingsStorage diff --git a/examples/integrations/microstream/greetings-mp/src/test/java/io/helidon/examples/integrations/microstream/greetings/mp/MicrostreamExampleGreetingsMpTest.java b/examples/integrations/microstream/greetings-mp/src/test/java/io/helidon/examples/integrations/microstream/greetings/mp/MicrostreamExampleGreetingsMpTest.java deleted file mode 100644 index fc613a1eaa5..00000000000 --- a/examples/integrations/microstream/greetings-mp/src/test/java/io/helidon/examples/integrations/microstream/greetings/mp/MicrostreamExampleGreetingsMpTest.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.microstream.greetings.mp; - -import java.nio.file.Path; - -import io.helidon.microprofile.testing.junit5.HelidonTest; - -import jakarta.inject.Inject; -import jakarta.ws.rs.client.WebTarget; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -@HelidonTest -class MicrostreamExampleGreetingsMpTest { - - @Inject - private WebTarget webTarget; - - @TempDir - static Path tempDir; - - @BeforeAll - static void beforeAll() { - System.setProperty("one.microstream.storage.greetings.storage-directory", tempDir.toString()); - } - - @Test - void testGreeting() { - GreetingMessage response = webTarget.path("/greet").request().get(GreetingMessage.class); - - assertEquals("Hello World!", response.getMessage(), "response should be 'Hello World' "); - } - -} diff --git a/examples/integrations/microstream/greetings-se/README.md b/examples/integrations/microstream/greetings-se/README.md deleted file mode 100644 index 358ca89397c..00000000000 --- a/examples/integrations/microstream/greetings-se/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Microstream integration example - -This example uses Microstream to persist a log entry for every greeting - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-integrations-microstream-greetings-se.jar -``` - -## Endpoints - -Get default greeting message: -```shell -curl -X GET http://localhost:8080/greet -``` - -Get greeting message for Joe: -```shell -curl -X GET http://localhost:8080/greet/Joe -``` - -Change greeting: -```shell -curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Howdy"}' http://localhost:8080/greet/greeting -``` - -Get the logs: -```shell -curl -X GET http://localhost:8080/greet/logs -``` \ No newline at end of file diff --git a/examples/integrations/microstream/greetings-se/pom.xml b/examples/integrations/microstream/greetings-se/pom.xml deleted file mode 100644 index 5ecd85e20a9..00000000000 --- a/examples/integrations/microstream/greetings-se/pom.xml +++ /dev/null @@ -1,106 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../../applications/se/pom.xml - - - helidon-examples-integrations-microstream-greetings-se - Helidon Examples Integration Microstream Greetings se - - - io.helidon.examples.integrations.microstream.greetings.se.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.integrations.microstream - helidon-integrations-microstream - - - io.helidon.webserver.observe - helidon-webserver-observe - - - io.helidon.http.media - helidon-http-media-jsonp - - - io.helidon.config - helidon-config-yaml - - - io.helidon.health - helidon-health-checks - - - io.helidon.metrics - helidon-metrics-api - - - io.helidon.webserver.observe - helidon-webserver-observe-metrics - runtime - - - io.helidon.metrics - helidon-metrics-system-meters - runtime - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/GreetingService.java b/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/GreetingService.java deleted file mode 100644 index 69dd6e1db95..00000000000 --- a/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/GreetingService.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.microstream.greetings.se; - -import java.util.Collections; -import java.util.concurrent.atomic.AtomicReference; -import java.util.logging.Logger; - -import io.helidon.config.Config; -import io.helidon.http.Status; -import io.helidon.integrations.microstream.core.EmbeddedStorageManagerBuilder; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -import jakarta.json.Json; -import jakarta.json.JsonArrayBuilder; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; - -/** - * 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 - *

      - * Get the logs: - * curl -X GET http://localhost:8080/greet/logs - *

      - * The message is returned as a JSON object - */ - -public class GreetingService implements HttpService { - - private final AtomicReference greeting = new AtomicReference<>(); - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - private static final Logger LOGGER = Logger.getLogger(GreetingService.class.getName()); - - private final GreetingServiceMicrostreamContext mctx; - - GreetingService(Config config) { - greeting.set(config.get("app.greeting").asString().orElse("Ciao")); - - mctx = new GreetingServiceMicrostreamContext(EmbeddedStorageManagerBuilder.create(config.get("microstream"))); - // we need to initialize the root element first - // if we do not wait here, we have a race where HTTP method may be invoked before we initialize root - mctx.start(); - mctx.initRootElement(); - } - - @Override - public void routing(HttpRules rules) { - rules.get("/", this::getDefaultMessageHandler) - .get("/logs", this::getLog) - .get("/{name}", this::getMessageHandler) - .put("/greeting", this::updateGreetingHandler); - } - - private void getLog(ServerRequest request, ServerResponse response) { - JsonArrayBuilder arrayBuilder = JSON.createArrayBuilder(); - mctx.getLogs().forEach((entry) -> arrayBuilder.add( - JSON.createObjectBuilder() - .add("name", entry.getName()) - .add("time", entry.getDateTime().toString()))); - response.send(arrayBuilder.build()); - } - - /** - * 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().pathParameters().get("name"); - sendResponse(response, name); - } - - private void sendResponse(ServerResponse response, String name) { - String msg = String.format("%s %s!", greeting.get(), name); - - mctx.addLogEntry(name); - - JsonObject returnObject = JSON.createObjectBuilder() - .add("message", msg) - .build(); - response.send(returnObject); - } - - private void updateGreetingFromJson(JsonObject jo, ServerResponse response) { - if (!jo.containsKey("greeting")) { - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "No greeting provided") - .build(); - response.status(Status.BAD_REQUEST_400) - .send(jsonErrorObject); - return; - } - - greeting.set(jo.getString("greeting")); - response.status(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) { - JsonObject jsonObject = request.content().as(JsonObject.class); - updateGreetingFromJson(jsonObject, response); - } - -} diff --git a/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/GreetingServiceMicrostreamContext.java b/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/GreetingServiceMicrostreamContext.java deleted file mode 100644 index b2a786e09fc..00000000000 --- a/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/GreetingServiceMicrostreamContext.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.microstream.greetings.se; - -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; - -import one.microstream.storage.embedded.types.EmbeddedStorageManager; - -/** - * This class extends {@link MicrostreamExecutionContext} and provides data access methods. - */ -public class GreetingServiceMicrostreamContext extends MicrostreamExecutionContext { - - /** - * Create a new instance. - * - * @param storageManager the EmbeddedStorageManager used. - */ - public GreetingServiceMicrostreamContext(EmbeddedStorageManager storageManager) { - super(storageManager); - } - - /** - * Add and store a new log entry. - * - * @param name parameter for log text. - */ - @SuppressWarnings({"unchecked", "resource"}) - public void addLogEntry(String name) { - List logs = (List) storageManager().root(); - logs.add(new LogEntry(name, LocalDateTime.now())); - storageManager().store(logs); - } - - /** - * initialize the storage root with a new, empty List. - */ - @SuppressWarnings("resource") - public void initRootElement() { - if (storageManager().root() == null) { - storageManager().setRoot(new ArrayList()); - storageManager().storeRoot(); - } - } - - /** - * returns a List of all stored LogEntries. - * - * @return all LogEntries. - */ - @SuppressWarnings({"unchecked", "resource"}) - public List getLogs() { - return (List) storageManager().root(); - } - -} diff --git a/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/LogEntry.java b/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/LogEntry.java deleted file mode 100644 index df0b73621f7..00000000000 --- a/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/LogEntry.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2021 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.integrations.microstream.greetings.se; - -import java.time.LocalDateTime; - -/** - * - * simple POJO that represents a Log entry that is stored by microstream in this example. - * - */ -public class LogEntry { - private String name; - private LocalDateTime dateTime; - - /** - * The Constructor. - * - * @param name name to be logged. - * - * @param dateTime dateTime date and time to be logged - */ - public LogEntry(String name, LocalDateTime dateTime) { - super(); - this.name = name; - this.dateTime = dateTime; - } - - public String getName() { - return name; - } - - public LocalDateTime getDateTime() { - return dateTime; - } - -} diff --git a/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/Main.java b/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/Main.java deleted file mode 100644 index 54f5bd1120f..00000000000 --- a/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/Main.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.microstream.greetings.se; - -import io.helidon.config.ClasspathConfigSource; -import io.helidon.config.Config; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.http.HttpRouting; - -/** - * Microstream demo with a simple rest application. - */ -public class Main { - - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * - * @param args command line arguments. - */ - public static void main(String[] args) { - WebServerConfig.Builder builder = WebServer.builder(); - setup(builder); - WebServer server = builder.build().start(); - System.out.println("WEB server is up! http://localhost:" + server.port() + "/greet"); - } - - static void setup(WebServerConfig.Builder server) { - LogConfig.configureRuntime(); - Config config = Config.builder() - .addSource(ClasspathConfigSource.create("/application.yaml")) - .build(); - - // Build server with JSONP support - server.config(config.get("server")) - .routing(r -> routing(r, config)); - } - - /** - * Setup routing. - * - * @param routing routing builder - * @param config configuration of this server - */ - static void routing(HttpRouting.Builder routing, Config config) { - GreetingService greetService = new GreetingService(config); - routing.register("/greet", greetService); - } -} diff --git a/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/MicrostreamExecutionContext.java b/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/MicrostreamExecutionContext.java deleted file mode 100644 index d319959405b..00000000000 --- a/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/MicrostreamExecutionContext.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.microstream.greetings.se; - -import one.microstream.reference.LazyReferenceManager; -import one.microstream.storage.embedded.types.EmbeddedStorageManager; - -/** - * Provides a very simply way to access a Microstream storage, and it's associated data. - */ -public class MicrostreamExecutionContext { - - private final EmbeddedStorageManager storage; - - /** - * Creates a new instance. - * - * @param storageManager the used EmbeddedStorageManager. - */ - public MicrostreamExecutionContext(EmbeddedStorageManager storageManager) { - this.storage = storageManager; - } - - /** - * returns the used storageManager. - * - * @return the used EmbeddedStorageManager. - */ - public EmbeddedStorageManager storageManager() { - return storage; - } - - /** - * Start the storage. - * - * @return the started EmbeddedStorageManager. - */ - public EmbeddedStorageManager start() { - return storage.start(); - } - - /** - * Shutdown the storage. - * - * @return the stopped EmbeddedStorageManager. - */ - public EmbeddedStorageManager shutdown() { - storage.shutdown(); - LazyReferenceManager.get().stop(); - return storage; - } - - /** - * Return the persistent object graph's root object. - * - * @param type of the root object - * @return the graph's root object casted to - */ - @SuppressWarnings("unchecked") - public T root() { - return (T) storage.root(); - } - - /** - * Sets the passed instance as the new root for the persistent object graph. - * - * @param object the new root object - * @return the new root object - */ - public Object setRoot(Object object) { - return storage.setRoot(object); - } - - /** - * Stores the registered root instance. - * - * @return the root instance's objectId. - */ - public long storeRoot() { - return storage.storeRoot(); - } - - /** - * Stores the passed object. - * - * @param object object to store - * @return the object id representing the passed instance. - */ - public long store(Object object) { - return storage.store(object); - } -} diff --git a/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/package-info.java b/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/package-info.java deleted file mode 100644 index c72da892914..00000000000 --- a/examples/integrations/microstream/greetings-se/src/main/java/io/helidon/examples/integrations/microstream/greetings/se/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 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. - */ - -/** - * An example that uses Microstream to persist a log entry for every greeting. - */ -package io.helidon.examples.integrations.microstream.greetings.se; diff --git a/examples/integrations/microstream/greetings-se/src/main/resources/application.yaml b/examples/integrations/microstream/greetings-se/src/main/resources/application.yaml deleted file mode 100644 index 425fd59d3f9..00000000000 --- a/examples/integrations/microstream/greetings-se/src/main/resources/application.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2021 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. -# - -app: - greeting: "Hello" - -server: - port: 8080 - host: 0.0.0.0 - -microstream: - channel-count: 4 - housekeeping-interval: 2000ms diff --git a/examples/integrations/microstream/greetings-se/src/test/java/io/helidon/examples/integrations/microstream/greetings/se/MicrostreamExampleGreetingsSeTest.java b/examples/integrations/microstream/greetings-se/src/test/java/io/helidon/examples/integrations/microstream/greetings/se/MicrostreamExampleGreetingsSeTest.java deleted file mode 100644 index 4c080135bc1..00000000000 --- a/examples/integrations/microstream/greetings-se/src/test/java/io/helidon/examples/integrations/microstream/greetings/se/MicrostreamExampleGreetingsSeTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.microstream.greetings.se; - -import java.nio.file.Path; - -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.WebServerConfig; - -import jakarta.json.JsonArray; -import jakarta.json.JsonObject; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.MatcherAssert.assertThat; - -@ServerTest -public class MicrostreamExampleGreetingsSeTest { - - @TempDir - static Path tempDir; - - private final Http1Client client; - - public MicrostreamExampleGreetingsSeTest(Http1Client client) { - this.client = client; - } - - @SetUpServer - static void setup(WebServerConfig.Builder server) { - System.setProperty("microstream.storage-directory", tempDir.toString()); - Main.setup(server); - } - - @Test - void testExample() { - try (Http1ClientResponse response = client.get("/greet/Joe").request()) { - assertThat(response.as(JsonObject.class).getString("message"), is("Hello Joe!")); - } - - try (Http1ClientResponse response = client.get("/greet/logs").request()) { - JsonArray jsonArray = response.as(JsonArray.class); - assertThat(jsonArray.get(0).asJsonObject().getString("name"), is("Joe")); - assertThat(jsonArray.get(0).asJsonObject().getString("time"), notNullValue()); - } - } -} diff --git a/examples/integrations/microstream/pom.xml b/examples/integrations/microstream/pom.xml deleted file mode 100644 index 8f3ab5b3625..00000000000 --- a/examples/integrations/microstream/pom.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - 4.0.0 - - io.helidon.examples.integrations - helidon-examples-integrations-project - 4.1.0-SNAPSHOT - - - io.helidon.examples.integrations.microstream - helidon-examples-integrations-microstream-project - Helidon Examples Integration Microstreams - pom - - - greetings-se - greetings-mp - - \ No newline at end of file diff --git a/examples/integrations/neo4j/README.md b/examples/integrations/neo4j/README.md deleted file mode 100644 index 33060669bbb..00000000000 --- a/examples/integrations/neo4j/README.md +++ /dev/null @@ -1,38 +0,0 @@ -# Helidon SE integration with Neo4J example - -## Build and run - -Bring up a Neo4j instance via Docker - -```shell -docker run --publish=7474:7474 --publish=7687:7687 -e 'NEO4J_AUTH=neo4j/secret' neo4j:4.0 -``` - -Goto the Neo4j browser and play the first step of the movies graph: [`:play movies`](http://localhost:7474/browser/?cmd=play&arg=movies). - -Build and run with JDK20 -```shell -mvn package -java -jar target/helidon-examples-integration-neo4j.jar -``` - -Then access the rest API like this: - -````shell -curl localhost:8080/api/movies -```` - -# Health and metrics - -Neo4jSupport provides health checks and metrics reading from Neo4j. - -Enable them in the driver: -```yaml - pool: - metricsEnabled: true -``` - -```shell -curl localhost:8080/observe/health -curl localhost:8080/observe/metrics -``` diff --git a/examples/integrations/neo4j/pom.xml b/examples/integrations/neo4j/pom.xml deleted file mode 100644 index f6ef7be7819..00000000000 --- a/examples/integrations/neo4j/pom.xml +++ /dev/null @@ -1,133 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - helidon-examples-integration-neo4j - Helidon Examples Integrations Neo4j - - - io.helidon.examples.integrations.neo4j.Main - 5.12.0 - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.health - helidon-health-checks - - - io.helidon.http.media - helidon-http-media-jsonp - - - io.helidon.http.media - helidon-http-media-jsonb - - - io.helidon.config - helidon-config-yaml - - - io.helidon.webserver.observe - helidon-webserver-observe - - - io.helidon.webserver.observe - helidon-webserver-observe-health - - - io.helidon.webserver.observe - helidon-webserver-observe-metrics - - - io.helidon.metrics - helidon-metrics - - - io.helidon.integrations.neo4j - helidon-integrations-neo4j - - - io.helidon.integrations.neo4j - helidon-integrations-neo4j-health - - - io.helidon.integrations.neo4j - helidon-integrations-neo4j-metrics - - - io.helidon.logging - helidon-logging-jul - runtime - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - org.neo4j.test - neo4j-harness - ${neo4j-harness.version} - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - - diff --git a/examples/integrations/neo4j/src/main/java/io/helidon/examples/integrations/neo4j/Main.java b/examples/integrations/neo4j/src/main/java/io/helidon/examples/integrations/neo4j/Main.java deleted file mode 100644 index e3cd6d641fe..00000000000 --- a/examples/integrations/neo4j/src/main/java/io/helidon/examples/integrations/neo4j/Main.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.neo4j; - -import java.util.List; - -import io.helidon.config.Config; -import io.helidon.examples.integrations.neo4j.domain.MovieRepository; -import io.helidon.health.checks.DeadlockHealthCheck; -import io.helidon.health.checks.DiskSpaceHealthCheck; -import io.helidon.health.checks.HeapMemoryHealthCheck; -import io.helidon.integrations.neo4j.Neo4j; -import io.helidon.integrations.neo4j.health.Neo4jHealthCheck; -import io.helidon.integrations.neo4j.metrics.Neo4jMetricsSupport; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.observe.ObserveFeature; -import io.helidon.webserver.observe.health.HealthObserver; -import io.helidon.webserver.spi.ServerFeature; - -import org.neo4j.driver.Driver; - -import static io.helidon.webserver.http.HttpRouting.Builder; - -/** - * The application main class. - */ -public class Main { - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * - * @param args command line arguments. - */ - public static void main(String[] args) { - // load logging configuration - LogConfig.configureRuntime(); - - startServer(); - } - - static void startServer() { - Neo4j neo4j = Neo4j.create(Config.create().get("neo4j")); - Driver neo4jDriver = neo4j.driver(); - - WebServer server = WebServer.builder() - .featuresDiscoverServices(false) - .features(features(neo4jDriver)) - .routing(it -> routing(it, neo4jDriver)) - .build() - .start(); - - System.out.println("WEB server is up! http://localhost:" + server.port() + "/api/movies"); - } - - static List features(Driver neo4jDriver) { - Neo4jHealthCheck healthCheck = Neo4jHealthCheck.create(neo4jDriver); - return List.of(ObserveFeature.just(HealthObserver.builder() - .useSystemServices(false) - .addCheck(HeapMemoryHealthCheck.create()) - .addCheck(DiskSpaceHealthCheck.create()) - .addCheck(DeadlockHealthCheck.create()) - .addCheck(healthCheck) - .build())); - } - - /** - * Updates HTTP Routing. - */ - static void routing(Builder routing, Driver neo4jDriver) { - - - Neo4jMetricsSupport.builder() - .driver(neo4jDriver) - .build() - .initialize(); - - - MovieService movieService = new MovieService(new MovieRepository(neo4jDriver)); - - - - routing.register(movieService); - } -} - diff --git a/examples/integrations/neo4j/src/main/java/io/helidon/examples/integrations/neo4j/MovieService.java b/examples/integrations/neo4j/src/main/java/io/helidon/examples/integrations/neo4j/MovieService.java deleted file mode 100644 index b73879cdc67..00000000000 --- a/examples/integrations/neo4j/src/main/java/io/helidon/examples/integrations/neo4j/MovieService.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.neo4j; - -import io.helidon.examples.integrations.neo4j.domain.MovieRepository; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -/** - * The Movie service. - */ -public class MovieService implements HttpService { - - private final MovieRepository movieRepository; - - /** - * The movies service. - * - * @param movieRepository a movie repository. - */ - public MovieService(MovieRepository movieRepository) { - this.movieRepository = movieRepository; - } - - @Override - public void routing(HttpRules rules) { - rules.get("/api/movies", this::findMoviesHandler); - } - - private void findMoviesHandler(ServerRequest request, ServerResponse response) { - response.send(this.movieRepository.findAll()); - } -} diff --git a/examples/integrations/neo4j/src/main/java/io/helidon/examples/integrations/neo4j/domain/Actor.java b/examples/integrations/neo4j/src/main/java/io/helidon/examples/integrations/neo4j/domain/Actor.java deleted file mode 100644 index ee9d5d8e3e1..00000000000 --- a/examples/integrations/neo4j/src/main/java/io/helidon/examples/integrations/neo4j/domain/Actor.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2002-2020 "Neo4j," - * Neo4j Sweden AB [http://neo4j.com] - * This file is part of Neo4j. - * 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.integrations.neo4j.domain; - -import java.util.ArrayList; -import java.util.List; - -/* - * Helidon changes are under the copyright of: - * - * Copyright (c) 2021, 2023 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. - * - */ - -/** - * The Actor class. - * - * @author Michael Simons - */ -public class Actor { - - private final String name; - - private final List roles; - - /** - * Constructor for actor. - * - * @param name - * @param roles - */ - public Actor(String name, final List roles) { - this.name = name; - this.roles = new ArrayList<>(roles); - } - - public String getName() { - return name; - } - - public List getRoles() { - return roles; - } -} diff --git a/examples/integrations/neo4j/src/main/java/io/helidon/examples/integrations/neo4j/domain/Movie.java b/examples/integrations/neo4j/src/main/java/io/helidon/examples/integrations/neo4j/domain/Movie.java deleted file mode 100644 index 17c9ca519b8..00000000000 --- a/examples/integrations/neo4j/src/main/java/io/helidon/examples/integrations/neo4j/domain/Movie.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2002-2020 "Neo4j," - * Neo4j Sweden AB [http://neo4j.com] - * This file is part of Neo4j. - * 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.integrations.neo4j.domain; - -import java.util.ArrayList; -import java.util.List; - -/* - * Helidon changes are under the copyright of: - * - * Copyright (c) 2021, 2023 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. - * - */ - -/** - * The Movie class. - * - * @author Michael Simons - */ -public class Movie { - - private final String title; - - private final String description; - - private List actors = new ArrayList<>(); - - private List directors = new ArrayList<>(); - - private Integer released; - - /** - * Constructor for Movie. - * - * @param title - * @param description - */ - public Movie(String title, String description) { - this.title = title; - this.description = description; - } - - public String getTitle() { - return title; - } - - public List getActors() { - return actors; - } - - public void setActors(List actors) { - this.actors = actors; - } - - public String getDescription() { - return description; - } - - public List getDirectors() { - return directors; - } - - public void setDirectorss(List directors) { - this.directors = directors; - } - - public Integer getReleased() { - return released; - } - - public void setReleased(Integer released) { - this.released = released; - } -} diff --git a/examples/integrations/neo4j/src/main/java/io/helidon/examples/integrations/neo4j/domain/MovieRepository.java b/examples/integrations/neo4j/src/main/java/io/helidon/examples/integrations/neo4j/domain/MovieRepository.java deleted file mode 100644 index c7b6e3bcffd..00000000000 --- a/examples/integrations/neo4j/src/main/java/io/helidon/examples/integrations/neo4j/domain/MovieRepository.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2002-2020 "Neo4j," - * Neo4j Sweden AB [http://neo4j.com] - * This file is part of Neo4j. - * 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.integrations.neo4j.domain; - -import java.util.List; - -import org.neo4j.driver.Driver; -import org.neo4j.driver.Value; - -/* - * Helidon changes are under the copyright of: - * - * Copyright (c) 2021, 2024 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. - * - */ - -/** - * The Movie repository. - * - * @author Michael Simons - */ -public final class MovieRepository { - - private final Driver driver; - - /** - * Constructor for the repo. - * - * @param driver - */ - public MovieRepository(Driver driver) { - this.driver = driver; - } - - /** - * Returns all the movies. - * @return List with movies - */ - public List findAll(){ - - try (var session = driver.session()) { - - var query = "" - + "match (m:Movie) " - + "match (m) <- [:DIRECTED] - (d:Person) " - + "match (m) <- [r:ACTED_IN] - (a:Person) " - + "return m, collect(d) as directors, collect({name:a.name, roles: r.roles}) as actors"; - - return session.executeRead(tx -> tx.run(query).list(r -> { - var movieNode = r.get("m").asNode(); - - var directors = r.get("directors").asList(v -> { - var personNode = v.asNode(); - return new Person(personNode.get("born").asInt(), personNode.get("name").asString()); - }); - - var actors = r.get("actors").asList(v -> { - return new Actor(v.get("name").asString(), v.get("roles").asList(Value::asString)); - }); - - var m = new Movie(movieNode.get("title").asString(), movieNode.get("tagline").asString()); - m.setReleased(movieNode.get("released").asInt()); - m.setDirectorss(directors); - m.setActors(actors); - return m; - })); - } - } -} diff --git a/examples/integrations/neo4j/src/main/java/io/helidon/examples/integrations/neo4j/domain/Person.java b/examples/integrations/neo4j/src/main/java/io/helidon/examples/integrations/neo4j/domain/Person.java deleted file mode 100644 index 5fb2a1abe45..00000000000 --- a/examples/integrations/neo4j/src/main/java/io/helidon/examples/integrations/neo4j/domain/Person.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2002-2020 "Neo4j," - * Neo4j Sweden AB [http://neo4j.com] - * This file is part of Neo4j. - * 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.integrations.neo4j.domain; - -/* - * Helidon changes are under the copyright of: - * - * Copyright (c) 2021, 2023 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. - * - */ - -/** - * The Person class. - * - * @author Michael Simons - */ -public class Person { - - private final String name; - - private Integer born; - - /** - * Constrictor for person. - * @param born - * @param name - */ - public Person(Integer born, String name) { - this.born = born; - this.name = name; - } - - public String getName() { - return name; - } - - public Integer getBorn() { - return born; - } - - public void setBorn(Integer born) { - this.born = born; - } - - @SuppressWarnings("checkstyle:OperatorWrap") - @Override - public String toString() { - return "Person{" + - "name='" + name + '\'' + - ", born=" + born + - '}'; - } -} diff --git a/examples/integrations/neo4j/src/main/java/io/helidon/examples/integrations/neo4j/domain/package-info.java b/examples/integrations/neo4j/src/main/java/io/helidon/examples/integrations/neo4j/domain/package-info.java deleted file mode 100644 index 215caf712f1..00000000000 --- a/examples/integrations/neo4j/src/main/java/io/helidon/examples/integrations/neo4j/domain/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2023 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. - */ - -/** - * Domain objects for movies. - */ -package io.helidon.examples.integrations.neo4j.domain; diff --git a/examples/integrations/neo4j/src/main/java/io/helidon/examples/integrations/neo4j/package-info.java b/examples/integrations/neo4j/src/main/java/io/helidon/examples/integrations/neo4j/package-info.java deleted file mode 100644 index 6d132dbc7eb..00000000000 --- a/examples/integrations/neo4j/src/main/java/io/helidon/examples/integrations/neo4j/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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. - */ - -/** - * Helidon Integrations Neo4j Example. - *

      - * - * @see io.helidon.examples.integrations.neo4j.Main - */ -package io.helidon.examples.integrations.neo4j; diff --git a/examples/integrations/neo4j/src/main/resources/application.yaml b/examples/integrations/neo4j/src/main/resources/application.yaml deleted file mode 100644 index 63f95335305..00000000000 --- a/examples/integrations/neo4j/src/main/resources/application.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# -# Copyright (c) 2021, 2023 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 - - -neo4j: - uri: bolt://localhost:7687 - authentication: - username: neo4j - password: secret - pool: - metricsEnabled: true diff --git a/examples/integrations/neo4j/src/main/resources/logging.properties b/examples/integrations/neo4j/src/main/resources/logging.properties deleted file mode 100644 index 41ffb45a3be..00000000000 --- a/examples/integrations/neo4j/src/main/resources/logging.properties +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright (c) 2021, 2023 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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 diff --git a/examples/integrations/neo4j/src/test/java/io/helidon/examples/integrations/neo4j/MainTest.java b/examples/integrations/neo4j/src/test/java/io/helidon/examples/integrations/neo4j/MainTest.java deleted file mode 100644 index 8391b79cc63..00000000000 --- a/examples/integrations/neo4j/src/test/java/io/helidon/examples/integrations/neo4j/MainTest.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.neo4j; - -import io.helidon.http.Status; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; - -import jakarta.json.JsonArray; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.neo4j.driver.Config; -import org.neo4j.driver.Driver; -import org.neo4j.driver.GraphDatabase; -import org.neo4j.harness.Neo4j; -import org.neo4j.harness.Neo4jBuilders; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Main test class for Neo4j Helidon SE application. - */ -@ServerTest -public class MainTest { - - static final String FIXTURE = """ - CREATE (TheMatrix:Movie {title:'The Matrix', released:1999, tagline:'Welcome to the Real World'}) - CREATE (Keanu:Person {name:'Keanu Reeves', born:1964}) - CREATE (Carrie:Person {name:'Carrie-Anne Moss', born:1967}) - CREATE (Laurence:Person {name:'Laurence Fishburne', born:1961}) - CREATE (Hugo:Person {name:'Hugo Weaving', born:1960}) - CREATE (LillyW:Person {name:'Lilly Wachowski', born:1967}) - CREATE (LanaW:Person {name:'Lana Wachowski', born:1965}) - CREATE (JoelS:Person {name:'Joel Silver', born:1952}) - CREATE (KevinB:Person {name:'Kevin Bacon', born:1958}) - CREATE - (Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrix), - (Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrix), - (Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrix), - (Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrix), - (LillyW)-[:DIRECTED]->(TheMatrix), - (LanaW)-[:DIRECTED]->(TheMatrix), - (JoelS)-[:PRODUCED]->(TheMatrix) - - CREATE (Emil:Person {name:"Emil Eifrem", born:1978}) - CREATE (Emil)-[:ACTED_IN {roles:["Emil"]}]->(TheMatrix) - - CREATE (TheMatrixReloaded:Movie {title:'The Matrix Reloaded', released:2003, tagline:'Free your mind'}) - CREATE - (Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrixReloaded), - (Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrixReloaded), - (Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrixReloaded), - (Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrixReloaded), - (LillyW)-[:DIRECTED]->(TheMatrixReloaded), - (LanaW)-[:DIRECTED]->(TheMatrixReloaded), - (JoelS)-[:PRODUCED]->(TheMatrixReloaded) - - CREATE (TheMatrixRevolutions:Movie {title:'The Matrix Revolutions', released:2003, - tagline:'Everything that has a beginning has an end'}) - CREATE - (Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrixRevolutions), - (Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrixRevolutions), - (Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrixRevolutions), - (KevinB)-[:ACTED_IN {roles:['Unknown']}]->(TheMatrixRevolutions), - (Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrixRevolutions), - (LillyW)-[:DIRECTED]->(TheMatrixRevolutions), - (LanaW)-[:DIRECTED]->(TheMatrixRevolutions), - (JoelS)-[:PRODUCED]->(TheMatrixRevolutions)"""; - private static Neo4j embeddedDatabaseServer; - private final Http1Client webClient; - - public MainTest(Http1Client webClient) { - this.webClient = webClient; - } - - @SetUpServer - static void server(WebServerConfig.Builder server) { - //Setup embedded Neo4j Server and inject in routing - embeddedDatabaseServer = Neo4jBuilders.newInProcessBuilder() - .withDisabledServer() - .withFixture(FIXTURE) - .build(); - - Driver driver = GraphDatabase.driver(embeddedDatabaseServer.boltURI(), Config.builder() - .withDriverMetrics() - .build()); - server.features(Main.features(driver)) - .routing(it -> Main.routing(it, driver)); - - } - - @BeforeAll - static void startServer() { - //Setup embedded Neo4j Server and inject in routing - embeddedDatabaseServer = Neo4jBuilders.newInProcessBuilder() - .withDisabledServer() - .withFixture(FIXTURE) - .build(); - - System.setProperty("neo4j.uri", embeddedDatabaseServer.boltURI().toString()); - } - - @AfterAll - static void stopServer() { - if (embeddedDatabaseServer != null) { - embeddedDatabaseServer.close(); - } - } - - @Test - public void testHealth() { - try (Http1ClientResponse response = webClient.get("/observe/health").request()) { - assertThat(response.status(), is(Status.NO_CONTENT_204)); - } - } - - @Test - void testMovies() { - JsonArray result = webClient.get("/api/movies").requestEntity(JsonArray.class); - assertThat(result.getJsonObject(0).getString("title"), containsString("The Matrix")); - } -} \ No newline at end of file diff --git a/examples/integrations/neo4j/src/test/java/io/helidon/examples/integrations/neo4j/package-info.java b/examples/integrations/neo4j/src/test/java/io/helidon/examples/integrations/neo4j/package-info.java deleted file mode 100644 index e9d169770e5..00000000000 --- a/examples/integrations/neo4j/src/test/java/io/helidon/examples/integrations/neo4j/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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. - */ - -/** - * Tests for Helidon Integrations Neo4j Example. - */ -package io.helidon.examples.integrations.neo4j; diff --git a/examples/integrations/oci/README.md b/examples/integrations/oci/README.md deleted file mode 100644 index fe566dd162f..00000000000 --- a/examples/integrations/oci/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# OCI Java SDK Examples - -```shell -mvn package -``` diff --git a/examples/integrations/oci/atp-cdi/README.md b/examples/integrations/oci/atp-cdi/README.md deleted file mode 100644 index 2af41874955..00000000000 --- a/examples/integrations/oci/atp-cdi/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# Helidon ATP MP Examples - -This example demonstrates how user can easily retrieve wallet from their ATP instance running in OCI and use information from that wallet to setup DataSource to do Database operations. - -It requires a running OCI ATP instance. - -Before running the test, make sure to update required properties in `application.yaml` - -- oci.atp.ocid: This is OCID of your running ATP instance. -- oci.atp.walletPassword: password to encrypt the keys inside the wallet. The password must be at least 8 characters long and must include at least 1 letter and either 1 numeric character or 1 special character. -- oracle.ucp.jdbc.PoolDataSource.atp.tnsNetServiceName: netServiceName of your database running inside OCI ATP as can be found in `tnsnames.ora` file. -- oracle.ucp.jdbc.PoolDataSource.atp.user: User to access your database running inside OCI ATP. -- oracle.ucp.jdbc.PoolDataSource.atp.password: Password of user to access your database running inside OCI ATP. - -Once you have updated required properties, you can run the example: - -```shell -mvn package -java -jar ./target/helidon-examples-integrations-oci-atp-cdi.jar -``` - -To verify that, you can retrieve wallet and do database operation: - -```shell -curl http://localhost:8080/atp/wallet -``` - -You should see `Hello world!!` \ No newline at end of file diff --git a/examples/integrations/oci/atp-cdi/pom.xml b/examples/integrations/oci/atp-cdi/pom.xml deleted file mode 100644 index 484b2ad1778..00000000000 --- a/examples/integrations/oci/atp-cdi/pom.xml +++ /dev/null @@ -1,95 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../../applications/mp/pom.xml - - - io.helidon.examples.integrations.oci - helidon-examples-integrations-oci-atp-cdi - Helidon Examples Integration OCI ATP CDI - CDI integration with OCI ATP. - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.integrations.cdi - helidon-integrations-cdi-datasource-ucp - - - io.helidon.integrations.db - ojdbc - - - com.oracle.database.jdbc - ucp - - - io.helidon.integrations.oci.sdk - helidon-integrations-oci-sdk-cdi - runtime - - - com.oracle.oci.sdk - oci-java-sdk-database - - - io.helidon.config - helidon-config-yaml-mp - - - io.smallrye - jandex - runtime - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/integrations/oci/atp-cdi/src/main/java/io/helidon/examples/integrations/oci/atp/cdi/AtpResource.java b/examples/integrations/oci/atp-cdi/src/main/java/io/helidon/examples/integrations/oci/atp/cdi/AtpResource.java deleted file mode 100644 index 46bdfdc6917..00000000000 --- a/examples/integrations/oci/atp-cdi/src/main/java/io/helidon/examples/integrations/oci/atp/cdi/AtpResource.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.oci.atp.cdi; - -import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.security.KeyStore; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.Objects; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; - -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManagerFactory; - -import com.oracle.bmc.database.Database; -import com.oracle.bmc.database.model.GenerateAutonomousDatabaseWalletDetails; -import com.oracle.bmc.database.requests.GenerateAutonomousDatabaseWalletRequest; -import com.oracle.bmc.database.responses.GenerateAutonomousDatabaseWalletResponse; -import com.oracle.bmc.http.client.Options; -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.core.Response; -import oracle.security.pki.OraclePKIProvider; -import oracle.ucp.jdbc.PoolDataSource; -import org.eclipse.microprofile.config.inject.ConfigProperty; -/** - * JAX-RS resource - REST API for the atp example. - */ -@Path("/atp") -public class AtpResource { - private static final Logger LOGGER = Logger.getLogger(AtpResource.class.getName()); - - private final Database databaseClient; - private final PoolDataSource atpDataSource; - private final String atpTnsNetServiceName; - - private final String atpOcid; - private final String walletPassword; - - @Inject - AtpResource(Database databaseClient, @Named("atp") PoolDataSource atpDataSource, - @ConfigProperty(name = "oracle.ucp.jdbc.PoolDataSource.atp.tnsNetServiceName") String atpTnsNetServiceName, - @ConfigProperty(name = "oci.atp.ocid") String atpOcid, - @ConfigProperty(name = "oci.atp.walletPassword") String walletPassword) { - this.databaseClient = databaseClient; - this.atpDataSource = Objects.requireNonNull(atpDataSource); - this.atpTnsNetServiceName = atpTnsNetServiceName; - this.atpOcid = atpOcid; - this.walletPassword = walletPassword; - } - - /** - * Generate wallet file for the configured ATP. - * - * @return response containing wallet file - */ - @GET - @Path("/wallet") - public Response generateWallet() { - Options.shouldAutoCloseResponseInputStream(false); - GenerateAutonomousDatabaseWalletResponse walletResponse = - databaseClient.generateAutonomousDatabaseWallet( - GenerateAutonomousDatabaseWalletRequest.builder() - .autonomousDatabaseId(this.atpOcid) - .generateAutonomousDatabaseWalletDetails( - GenerateAutonomousDatabaseWalletDetails.builder() - .password(this.walletPassword) - .build()) - .build()); - - if (walletResponse.getContentLength() == 0) { - LOGGER.log(Level.SEVERE, "GenerateAutonomousDatabaseWalletResponse is empty"); - return Response.status(Response.Status.NOT_FOUND).build(); - } - - byte[] walletContent = null; - try { - walletContent = walletResponse.getInputStream().readAllBytes(); - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Error processing GenerateAutonomousDatabaseWalletResponse", e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); - } - String returnEntity = null; - try { - this.atpDataSource.setSSLContext(getSSLContext(walletContent)); - this.atpDataSource.setURL(getJdbcUrl(walletContent, this.atpTnsNetServiceName)); - try ( - Connection connection = this.atpDataSource.getConnection(); - PreparedStatement ps = connection.prepareStatement("SELECT 'Hello world!!' FROM DUAL"); - ResultSet rs = ps.executeQuery() - ){ - rs.next(); - returnEntity = rs.getString(1); - } - } catch (SQLException e) { - LOGGER.log(Level.SEVERE, "Error setting up DataSource", e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); - } - - return Response.status(Response.Status.OK).entity(returnEntity).build(); - } - - /** - * Returns SSLContext based on cwallet.sso in wallet. - * - * @param walletContent - * @return SSLContext - */ - private static SSLContext getSSLContext(byte[] walletContent) throws IllegalStateException { - SSLContext sslContext = null; - try (ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new ByteArrayInputStream(walletContent)))) { - ZipEntry entry = null; - while ((entry = zis.getNextEntry()) != null) { - if (entry.getName().equals("cwallet.sso")) { - KeyStore keyStore = KeyStore.getInstance("SSO", new OraclePKIProvider()); - keyStore.load(zis, null); - TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX"); - KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("PKIX"); - trustManagerFactory.init(keyStore); - keyManagerFactory.init(keyStore, null); - sslContext = SSLContext.getInstance("TLS"); - sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); - } - zis.closeEntry(); - } - } catch (RuntimeException | Error throwMe) { - throw throwMe; - } catch (Exception e) { - throw new IllegalStateException("Error while getting SSLContext from wallet.", e); - } - return sslContext; - } - - /** - * Returns JDBC URL with connection description for the given service based on tnsnames.ora in wallet. - * - * @param walletContent - * @param tnsNetServiceName - * @return String - */ - private static String getJdbcUrl(byte[] walletContent, String tnsNetServiceName) throws IllegalStateException { - String jdbcUrl = null; - try (ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new ByteArrayInputStream(walletContent)))) { - ZipEntry entry = null; - while ((entry = zis.getNextEntry()) != null) { - if (entry.getName().equals("tnsnames.ora")) { - jdbcUrl = new String(zis.readAllBytes(), StandardCharsets.UTF_8) - .replaceFirst(tnsNetServiceName + "\\s*=\\s*", "jdbc:oracle:thin:@") - .replaceAll("\\n[^\\n]+", ""); - } - zis.closeEntry(); - } - } catch (IOException e) { - throw new IllegalStateException("Error while getting JDBC URL from wallet.", e); - } - return jdbcUrl; - } -} - diff --git a/examples/integrations/oci/atp-cdi/src/main/java/io/helidon/examples/integrations/oci/atp/cdi/package-info.java b/examples/integrations/oci/atp-cdi/src/main/java/io/helidon/examples/integrations/oci/atp/cdi/package-info.java deleted file mode 100644 index b8468161b7c..00000000000 --- a/examples/integrations/oci/atp-cdi/src/main/java/io/helidon/examples/integrations/oci/atp/cdi/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 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 of integration with OCI ATP in CDI application. - */ -package io.helidon.examples.integrations.oci.atp.cdi; diff --git a/examples/integrations/oci/atp-cdi/src/main/resources/META-INF/beans.xml b/examples/integrations/oci/atp-cdi/src/main/resources/META-INF/beans.xml deleted file mode 100644 index dbf3e648c1e..00000000000 --- a/examples/integrations/oci/atp-cdi/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/integrations/oci/atp-cdi/src/main/resources/application.yaml b/examples/integrations/oci/atp-cdi/src/main/resources/application.yaml deleted file mode 100644 index de8655b3d5b..00000000000 --- a/examples/integrations/oci/atp-cdi/src/main/resources/application.yaml +++ /dev/null @@ -1,37 +0,0 @@ -# -# Copyright (c) 2021, 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. -# - -# The values are read from -# ~/helidon/conf/examples.yaml -# or you can just update them here - -server: - port: 8080 - -oracle: - ucp: - jdbc: - PoolDataSource: - atp: - connectionFactoryClassName: oracle.jdbc.pool.OracleDataSource - tnsNetServiceName: "${atp.db.tnsNetServiceName}" - user: "${atp.db.user}" - password: "${atp.db.password}" - -oci: - atp: - ocid: "${oci.properties.atp-ocid}" - walletPassword: "${oci.properties.atp-walletPassword}" \ No newline at end of file diff --git a/examples/integrations/oci/atp-cdi/src/main/resources/logging.properties b/examples/integrations/oci/atp-cdi/src/main/resources/logging.properties deleted file mode 100644 index b4eb284e666..00000000000 --- a/examples/integrations/oci/atp-cdi/src/main/resources/logging.properties +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2021, 2023 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. -# - -# Send messages to the console -handlers=io.helidon.logging.jul.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 - -io.helidon.level=INFO -io.helidon.integrations.level=INFO -io.helidon.webclient.level=INFO diff --git a/examples/integrations/oci/atp/README.md b/examples/integrations/oci/atp/README.md deleted file mode 100644 index da82d2aa951..00000000000 --- a/examples/integrations/oci/atp/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# Helidon ATP SE Examples - -This example demonstrates how user can easily retrieve wallet from their ATP instance running in OCI and use information from that wallet to setup DataSource to do Database operations. - -It requires a running OCI ATP instance. - -Before running the test, make sure to update required properties in `application.yaml` - -- oci.atp.ocid: This is OCID of your running ATP instance. -- oci.atp.walletPassword: password to encrypt the keys inside the wallet. The password must be at least 8 characters long and must include at least 1 letter and either 1 numeric character or 1 special character. -- db.tnsNetServiceName: netServiceName of your database running inside OCI ATP as can be found in `tnsnames.ora` file. -- db.userName: User to access your database running inside OCI ATP. -- db.password: Password of user to access your database running inside OCI ATP. - -Once you have updated required properties, you can run the example: - -```shell -mvn package -java -jar ./target/helidon-examples-integrations-oci-atp.jar -``` - -To verify that, you can retrieve wallet and do database operation: - -```shell -curl http://localhost:8080/atp/wallet -``` - -You should see `Hello world!!` diff --git a/examples/integrations/oci/atp/pom.xml b/examples/integrations/oci/atp/pom.xml deleted file mode 100644 index c62df627331..00000000000 --- a/examples/integrations/oci/atp/pom.xml +++ /dev/null @@ -1,89 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../../applications/se/pom.xml - - - io.helidon.examples.integrations.oci - helidon-examples-integrations-oci-atp - Helidon Examples Integration OCI ATP - Integration with OCI ATP. - - - io.helidon.examples.integrations.oci.atp.OciAtpMain - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.dbclient - helidon-dbclient - - - io.helidon.dbclient - helidon-dbclient-jdbc - - - io.helidon.integrations.db - ojdbc - - - com.oracle.database.jdbc - ucp - - - io.helidon.config - helidon-config-yaml - - - com.oracle.oci.sdk - oci-java-sdk-database - - - com.oracle.oci.sdk - oci-java-sdk-common-httpclient-jersey3 - runtime - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/integrations/oci/atp/src/main/java/io/helidon/examples/integrations/oci/atp/AtpService.java b/examples/integrations/oci/atp/src/main/java/io/helidon/examples/integrations/oci/atp/AtpService.java deleted file mode 100644 index bfd342e7054..00000000000 --- a/examples/integrations/oci/atp/src/main/java/io/helidon/examples/integrations/oci/atp/AtpService.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.oci.atp; - -import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.security.KeyStore; -import java.sql.SQLException; -import java.util.Optional; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; - -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManagerFactory; - -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbRow; -import io.helidon.dbclient.jdbc.JdbcClientProvider; -import io.helidon.http.Status; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -import com.oracle.bmc.database.Database; -import com.oracle.bmc.database.model.GenerateAutonomousDatabaseWalletDetails; -import com.oracle.bmc.database.requests.GenerateAutonomousDatabaseWalletRequest; -import com.oracle.bmc.database.responses.GenerateAutonomousDatabaseWalletResponse; -import oracle.jdbc.pool.OracleDataSource; -import oracle.security.pki.OraclePKIProvider; -import oracle.ucp.jdbc.PoolDataSource; -import oracle.ucp.jdbc.PoolDataSourceFactory; - -class AtpService implements HttpService { - private static final Logger LOGGER = Logger.getLogger(AtpService.class.getName()); - - private final Database databaseClient; - private final Config config; - - AtpService(Database databaseClient, Config config) { - this.databaseClient = databaseClient; - this.config = config; - } - - @Override - public void routing(HttpRules rules) { - rules.get("/wallet", this::generateWallet); - } - - /** - * Generate wallet file for the configured ATP. - */ - private void generateWallet(ServerRequest req, ServerResponse res) { - String ocid = config.get("oci.atp.ocid").asString().get(); - GenerateAutonomousDatabaseWalletDetails walletDetails = - GenerateAutonomousDatabaseWalletDetails.builder() - .password(ocid) - .build(); - GenerateAutonomousDatabaseWalletResponse walletResponse = databaseClient - .generateAutonomousDatabaseWallet( - GenerateAutonomousDatabaseWalletRequest.builder() - .autonomousDatabaseId(ocid) - .generateAutonomousDatabaseWalletDetails(walletDetails) - .build()); - - if (walletResponse.getContentLength() == 0) { - LOGGER.log(Level.SEVERE, "GenerateAutonomousDatabaseWalletResponse is empty"); - res.status(Status.NOT_FOUND_404).send(); - return; - } - - byte[] walletContent; - try { - walletContent = walletResponse.getInputStream().readAllBytes(); - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Error processing GenerateAutonomousDatabaseWalletResponse", e); - res.status(Status.INTERNAL_SERVER_ERROR_500).send(); - return; - } - - DbClient dbClient = createDbClient(walletContent); - Optional row = dbClient.execute().query("SELECT 'Hello world!!' FROM DUAL").findFirst(); - if (row.isPresent()) { - res.send(row.get().column(1).as(String.class)); - } else { - res.status(404).send(); - } - } - - DbClient createDbClient(byte[] walletContent) { - PoolDataSource pds = PoolDataSourceFactory.getPoolDataSource(); - try { - pds.setSSLContext(getSSLContext(walletContent)); - pds.setURL(getJdbcUrl(walletContent, config.get("db.tnsNetServiceName") - .as(String.class) - .orElseThrow(() -> new IllegalStateException("Missing tnsNetServiceName!!")))); - pds.setUser(config.get("db.userName").as(String.class).orElse("ADMIN")); - pds.setPassword(config.get("db.password") - .as(String.class) - .orElseThrow(() -> new IllegalStateException("Missing password!!"))); - pds.setConnectionFactoryClassName(OracleDataSource.class.getName()); - } catch (SQLException e) { - LOGGER.log(Level.SEVERE, "Error setting up PoolDataSource", e); - throw new RuntimeException(e); - } - return new JdbcClientProvider().builder() - .connectionPool(() -> { - try { - return pds.getConnection(); - } catch (SQLException e) { - throw new IllegalStateException("Error while setting up new connection", e); - } - }) - .build(); - } - - /** - * Returns SSLContext based on cwallet.sso in wallet. - * - * @return SSLContext - */ - private static SSLContext getSSLContext(byte[] walletContent) throws IllegalStateException { - SSLContext sslContext = null; - try (ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new ByteArrayInputStream(walletContent)))) { - ZipEntry entry; - while ((entry = zis.getNextEntry()) != null) { - if (entry.getName().equals("cwallet.sso")) { - KeyStore keyStore = KeyStore.getInstance("SSO", new OraclePKIProvider()); - keyStore.load(zis, null); - TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX"); - KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("PKIX"); - trustManagerFactory.init(keyStore); - keyManagerFactory.init(keyStore, null); - sslContext = SSLContext.getInstance("TLS"); - sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); - } - zis.closeEntry(); - } - } catch (RuntimeException | Error throwMe) { - throw throwMe; - } catch (Exception e) { - throw new IllegalStateException("Error while getting SSLContext from wallet.", e); - } - return sslContext; - } - - /** - * Returns JDBC URL with connection description for the given service based on {@code tnsnames.ora} in wallet. - * - * @param walletContent walletContent - * @param tnsNetServiceName tnsNetServiceName - * @return String - */ - private static String getJdbcUrl(byte[] walletContent, String tnsNetServiceName) throws IllegalStateException { - String jdbcUrl = null; - try (ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new ByteArrayInputStream(walletContent)))) { - ZipEntry entry; - while ((entry = zis.getNextEntry()) != null) { - if (entry.getName().equals("tnsnames.ora")) { - jdbcUrl = new String(zis.readAllBytes(), StandardCharsets.UTF_8) - .replaceFirst(tnsNetServiceName + "\\s*=\\s*", "jdbc:oracle:thin:@") - .replaceAll("\\n[^\\n]+", ""); - } - zis.closeEntry(); - } - } catch (IOException e) { - throw new IllegalStateException("Error while getting JDBC URL from wallet.", e); - } - return jdbcUrl; - } -} diff --git a/examples/integrations/oci/atp/src/main/java/io/helidon/examples/integrations/oci/atp/OciAtpMain.java b/examples/integrations/oci/atp/src/main/java/io/helidon/examples/integrations/oci/atp/OciAtpMain.java deleted file mode 100644 index b14edebdc66..00000000000 --- a/examples/integrations/oci/atp/src/main/java/io/helidon/examples/integrations/oci/atp/OciAtpMain.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.oci.atp; - -import java.io.IOException; - -import io.helidon.config.Config; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; - -import com.oracle.bmc.ConfigFileReader; -import com.oracle.bmc.auth.AuthenticationDetailsProvider; -import com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider; -import com.oracle.bmc.database.Database; -import com.oracle.bmc.database.DatabaseClient; -import com.oracle.bmc.model.BmcException; - -/** - * Main class of the example. - * This example sets up a web server to serve REST API to retrieve ATP wallet. - */ -public final class OciAtpMain { - /** - * Cannot be instantiated. - */ - private OciAtpMain() { - } - - /** - * Application main entry point. - * - * @param args command line arguments. - */ - public static void main(String[] args) throws IOException { - // load logging configuration - LogConfig.configureRuntime(); - - // By default, this will pick up application.yaml from the classpath - Config config = Config.create(); - - // this requires OCI configuration in the usual place - // ~/.oci/config - ConfigFileReader.ConfigFile configFile = ConfigFileReader.parseDefault(); - AuthenticationDetailsProvider authProvider = new ConfigFileAuthenticationDetailsProvider(configFile); - Database databaseClient = DatabaseClient.builder().build(authProvider); - - // Prepare routing for the server - WebServer server = WebServer.builder() - .config(config.get("server")) - .routing(routing -> routing - .register("/atp", new AtpService(databaseClient, config)) - // OCI SDK error handling - .error(BmcException.class, (req, res, ex) -> - res.status(ex.getStatusCode()) - .send(ex.getMessage()))) - .build() - .start(); - - System.out.println("WEB server is up! http://localhost:" + server.port() + "/"); - } -} diff --git a/examples/integrations/oci/atp/src/main/java/io/helidon/examples/integrations/oci/atp/package-info.java b/examples/integrations/oci/atp/src/main/java/io/helidon/examples/integrations/oci/atp/package-info.java deleted file mode 100644 index e09431d39be..00000000000 --- a/examples/integrations/oci/atp/src/main/java/io/helidon/examples/integrations/oci/atp/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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 of integration with OCI ATP in a Helidon SE application. - */ -package io.helidon.examples.integrations.oci.atp; diff --git a/examples/integrations/oci/atp/src/main/resources/application.yaml b/examples/integrations/oci/atp/src/main/resources/application.yaml deleted file mode 100644 index b65d90eccd2..00000000000 --- a/examples/integrations/oci/atp/src/main/resources/application.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# -# Copyright (c) 2021, 2023 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. -# - -# The values are read from -# ~/helidon/conf/examples.yaml -# or you can just update them here - -server: - port: 8080 - -db: - userName: "${atp.db.userName}" - password: "${atp.db.password}" - tnsNetServiceName: "${atp.db.tnsNetServiceName}" - -oci: - atp: - ocid: "${oci.properties.atp-ocid}" - walletPassword: "${oci.properties.atp-walletPassword}" diff --git a/examples/integrations/oci/atp/src/main/resources/logging.properties b/examples/integrations/oci/atp/src/main/resources/logging.properties deleted file mode 100644 index b4eb284e666..00000000000 --- a/examples/integrations/oci/atp/src/main/resources/logging.properties +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2021, 2023 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. -# - -# Send messages to the console -handlers=io.helidon.logging.jul.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 - -io.helidon.level=INFO -io.helidon.integrations.level=INFO -io.helidon.webclient.level=INFO diff --git a/examples/integrations/oci/metrics/README.md b/examples/integrations/oci/metrics/README.md deleted file mode 100644 index 53a11340080..00000000000 --- a/examples/integrations/oci/metrics/README.md +++ /dev/null @@ -1,9 +0,0 @@ -The metrics example. - -The example requires OCI config in some default place like ``.oci/config`` - -Build and run the example by -```shell -mvn package -java -jar ./target/helidon-examples-integrations-oci-metrics.jar -``` diff --git a/examples/integrations/oci/metrics/pom.xml b/examples/integrations/oci/metrics/pom.xml deleted file mode 100644 index f3a488af9eb..00000000000 --- a/examples/integrations/oci/metrics/pom.xml +++ /dev/null @@ -1,73 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../../applications/se/pom.xml - - - - io.helidon.examples.integrations.oci.telemetry.OciMetricsMain - - - io.helidon.examples.integrations.oci - helidon-examples-integrations-oci-metrics - Helidon Examples Integration OCI Metrics - Integration with OCI Metrics. - - - - io.helidon.config - helidon-config-yaml - - - io.helidon.logging - helidon-logging-jul - - - com.oracle.oci.sdk - oci-java-sdk-monitoring - - - com.oracle.oci.sdk - oci-java-sdk-common-httpclient-jersey3 - runtime - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/integrations/oci/metrics/src/main/java/io/helidon/examples/integrations/oci/telemetry/OciMetricsMain.java b/examples/integrations/oci/metrics/src/main/java/io/helidon/examples/integrations/oci/telemetry/OciMetricsMain.java deleted file mode 100644 index 463604d1d30..00000000000 --- a/examples/integrations/oci/metrics/src/main/java/io/helidon/examples/integrations/oci/telemetry/OciMetricsMain.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.oci.telemetry; - -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import java.util.Date; -import java.util.List; -import java.util.Map; - -import io.helidon.config.Config; -import io.helidon.logging.common.LogConfig; - -import com.oracle.bmc.ConfigFileReader; -import com.oracle.bmc.auth.AuthenticationDetailsProvider; -import com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider; -import com.oracle.bmc.monitoring.Monitoring; -import com.oracle.bmc.monitoring.MonitoringClient; -import com.oracle.bmc.monitoring.model.Datapoint; -import com.oracle.bmc.monitoring.model.FailedMetricRecord; -import com.oracle.bmc.monitoring.model.MetricDataDetails; -import com.oracle.bmc.monitoring.model.PostMetricDataDetails; -import com.oracle.bmc.monitoring.model.PostMetricDataResponseDetails; -import com.oracle.bmc.monitoring.requests.PostMetricDataRequest; -import com.oracle.bmc.monitoring.responses.PostMetricDataResponse; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.file; - -/** - * OCI Metrics example. - */ -public final class OciMetricsMain { - - private OciMetricsMain() { - } - - /** - * Main method. - * - * @param args ignored - */ - public static void main(String[] args) throws Exception { - LogConfig.configureRuntime(); - // as I cannot share my configuration of OCI, let's combine the configuration - // from my home directory with the one compiled into the jar - // when running this example, you can either update the application.yaml in resources directory - // or use the same approach - Config config = buildConfig(); - - // this requires OCI configuration in the usual place - // ~/.oci/config - AuthenticationDetailsProvider authProvider = new ConfigFileAuthenticationDetailsProvider(ConfigFileReader.parseDefault()); - try (Monitoring monitoringClient = MonitoringClient.builder().build(authProvider)) { - monitoringClient.setEndpoint(monitoringClient.getEndpoint().replace("telemetry.", "telemetry-ingestion.")); - - PostMetricDataRequest postMetricDataRequest = PostMetricDataRequest.builder() - .postMetricDataDetails(getPostMetricDataDetails(config)) - .build(); - - // Invoke the API call. - PostMetricDataResponse postMetricDataResponse = monitoringClient.postMetricData(postMetricDataRequest); - PostMetricDataResponseDetails postMetricDataResponseDetails = postMetricDataResponse - .getPostMetricDataResponseDetails(); - int count = postMetricDataResponseDetails.getFailedMetricsCount(); - System.out.println("Failed count: " + count); - if (count > 0) { - System.out.println("Failed metrics:"); - for (FailedMetricRecord failedMetric : postMetricDataResponseDetails.getFailedMetrics()) { - System.out.println("\t" + failedMetric.getMessage() + ": " + failedMetric.getMetricData()); - } - } - } - } - - private static PostMetricDataDetails getPostMetricDataDetails(Config config) { - String compartmentId = config.get("oci.metrics.compartment-ocid").asString().get(); - Instant now = Instant.now(); - return PostMetricDataDetails.builder() - .metricData(List.of( - MetricDataDetails.builder() - .compartmentId(compartmentId) - // Add a few data points to see something in the console - .datapoints(List.of( - Datapoint.builder() - .timestamp(Date.from(now.minus(10, ChronoUnit.SECONDS))) - .value(101.00) - .build(), - Datapoint.builder() - .timestamp(Date.from(now)) - .value(149.00) - .build() - )) - .dimensions(Map.of( - "resourceId", "myresourceid", - "unit", "cm")) - .name("my_app.jump") - .namespace("helidon_examples") - .build() - )) - .batchAtomicity(PostMetricDataDetails.BatchAtomicity.NonAtomic).build(); - } - - private static Config buildConfig() { - return Config.builder() - .sources( - // you can use this file to override the defaults that are built-in - file(System.getProperty("user.home") + "/helidon/conf/examples.yaml").optional(), - // in jar file (see src/main/resources/application.yaml) - classpath("application.yaml")) - .build(); - } -} diff --git a/examples/integrations/oci/metrics/src/main/java/io/helidon/examples/integrations/oci/telemetry/package-info.java b/examples/integrations/oci/metrics/src/main/java/io/helidon/examples/integrations/oci/telemetry/package-info.java deleted file mode 100644 index 3fc15dd7d8a..00000000000 --- a/examples/integrations/oci/metrics/src/main/java/io/helidon/examples/integrations/oci/telemetry/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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 using OCI metrics blocking API. - */ -package io.helidon.examples.integrations.oci.telemetry; diff --git a/examples/integrations/oci/metrics/src/main/resources/application.yaml b/examples/integrations/oci/metrics/src/main/resources/application.yaml deleted file mode 100644 index c2c669e26ca..00000000000 --- a/examples/integrations/oci/metrics/src/main/resources/application.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2021, 2023 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. -# - -# The values are read from -# ~/helidon/conf/examples.yaml -# or you can just update them here -oci: - metrics: - compartment-ocid: "${oci.properties.compartment-ocid}" - diff --git a/examples/integrations/oci/metrics/src/main/resources/logging.properties b/examples/integrations/oci/metrics/src/main/resources/logging.properties deleted file mode 100644 index 341cef8ce9e..00000000000 --- a/examples/integrations/oci/metrics/src/main/resources/logging.properties +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright (c) 2021, 2023 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. -# - -# Send messages to the console -handlers=io.helidon.logging.jul.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 - -io.helidon.level=INFO -io.helidon.integrations.level=INFO diff --git a/examples/integrations/oci/objectstorage-cdi/README.md b/examples/integrations/oci/objectstorage-cdi/README.md deleted file mode 100644 index aa08fbe0c61..00000000000 --- a/examples/integrations/oci/objectstorage-cdi/README.md +++ /dev/null @@ -1,11 +0,0 @@ -The object storage (CDI) example. - -The example requires OCI config in some default place like ``.oci/config`` -Also properties from the ``src/main/resources/application.yaml`` shall be configured. -Like ``oci.objectstorage.bucketName`` - -Build and run the example by -```shell -mvn package -java -jar ./target/helidon-examples-integrations-oci-objectstorage-cdi.jar -``` diff --git a/examples/integrations/oci/objectstorage-cdi/pom.xml b/examples/integrations/oci/objectstorage-cdi/pom.xml deleted file mode 100644 index 4e1d155d4da..00000000000 --- a/examples/integrations/oci/objectstorage-cdi/pom.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../../applications/mp/pom.xml - - - io.helidon.examples.integrations.oci - helidon-examples-integrations-oci-objectstorage-cdi - Helidon Examples Integration OCI Object Storage CDI - CDI integration with OCI Object Storage. - - - io.helidon.examples.integrations.oci.objectstorage.cdi.ObjectStorageCdiMain - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.integrations.oci.sdk - helidon-integrations-oci-sdk-cdi - - - com.oracle.oci.sdk - oci-java-sdk-objectstorage - - - io.helidon.config - helidon-config-yaml-mp - - - io.smallrye - jandex - runtime - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - - diff --git a/examples/integrations/oci/objectstorage-cdi/src/main/java/io/helidon/examples/integrations/oci/objectstorage/cdi/ObjectStorageCdiMain.java b/examples/integrations/oci/objectstorage-cdi/src/main/java/io/helidon/examples/integrations/oci/objectstorage/cdi/ObjectStorageCdiMain.java deleted file mode 100644 index 4d99c4a9ebd..00000000000 --- a/examples/integrations/oci/objectstorage-cdi/src/main/java/io/helidon/examples/integrations/oci/objectstorage/cdi/ObjectStorageCdiMain.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2021 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.integrations.oci.objectstorage.cdi; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; - -import io.helidon.config.yaml.mp.YamlMpConfigSource; -import io.helidon.microprofile.cdi.Main; - -import org.eclipse.microprofile.config.Config; -import org.eclipse.microprofile.config.spi.ConfigProviderResolver; -import org.eclipse.microprofile.config.spi.ConfigSource; - -/** - * Main class of the example. - * This is only used to merge configuration from home directory with the one embedded on classpath. - */ -public final class ObjectStorageCdiMain { - private ObjectStorageCdiMain() { - } - - /** - * Main method. - * - * @param args ignored - */ - public static void main(String[] args) { - ConfigProviderResolver configProvider = ConfigProviderResolver.instance(); - - Config mpConfig = configProvider.getBuilder() - .addDefaultSources() - .withSources(examplesConfig()) - .addDiscoveredSources() - .addDiscoveredConverters() - .build(); - - // configure - configProvider.registerConfig(mpConfig, null); - - // start CDI - Main.main(args); - } - - private static ConfigSource[] examplesConfig() { - Path path = Paths.get(System.getProperty("user.home") + "/helidon/conf/examples.yaml"); - if (Files.exists(path)) { - return new ConfigSource[] {YamlMpConfigSource.create(path)}; - } - return new ConfigSource[0]; - } -} diff --git a/examples/integrations/oci/objectstorage-cdi/src/main/java/io/helidon/examples/integrations/oci/objectstorage/cdi/ObjectStorageResource.java b/examples/integrations/oci/objectstorage-cdi/src/main/java/io/helidon/examples/integrations/oci/objectstorage/cdi/ObjectStorageResource.java deleted file mode 100644 index 6b753a47900..00000000000 --- a/examples/integrations/oci/objectstorage-cdi/src/main/java/io/helidon/examples/integrations/oci/objectstorage/cdi/ObjectStorageResource.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.oci.objectstorage.cdi; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.helidon.http.HeaderNames; - -import com.oracle.bmc.objectstorage.ObjectStorage; -import com.oracle.bmc.objectstorage.requests.DeleteObjectRequest; -import com.oracle.bmc.objectstorage.requests.GetNamespaceRequest; -import com.oracle.bmc.objectstorage.requests.GetObjectRequest; -import com.oracle.bmc.objectstorage.requests.PutObjectRequest; -import com.oracle.bmc.objectstorage.responses.DeleteObjectResponse; -import com.oracle.bmc.objectstorage.responses.GetNamespaceResponse; -import com.oracle.bmc.objectstorage.responses.GetObjectResponse; -import com.oracle.bmc.objectstorage.responses.PutObjectResponse; -import jakarta.inject.Inject; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.core.Response; -import org.eclipse.microprofile.config.inject.ConfigProperty; - -/** - * JAX-RS resource - REST API for the objecstorage example. - */ -@Path("/files") -public class ObjectStorageResource { - private static final Logger LOGGER = Logger.getLogger(ObjectStorageResource.class.getName()); - private final ObjectStorage objectStorageClient; - private final String namespaceName; - private final String bucketName; - - @Inject - ObjectStorageResource(ObjectStorage objectStorageClient, - @ConfigProperty(name = "oci.objectstorage.bucketName") - String bucketName) { - this.objectStorageClient = objectStorageClient; - this.bucketName = bucketName; - GetNamespaceResponse namespaceResponse = - this.objectStorageClient.getNamespace(GetNamespaceRequest.builder().build()); - this.namespaceName = namespaceResponse.getValue(); - } - - /** - * Download a file from object storage. - * - * @param fileName name of the object - * @return response - */ - @GET - @Path("/file/{file-name}") - public Response download(@PathParam("file-name") String fileName) { - GetObjectResponse getObjectResponse = - objectStorageClient.getObject( - GetObjectRequest.builder() - .namespaceName(namespaceName) - .bucketName(bucketName) - .objectName(fileName) - .build()); - - if (getObjectResponse.getContentLength() == 0) { - LOGGER.log(Level.SEVERE, "GetObjectResponse is empty"); - return Response.status(Response.Status.NOT_FOUND).build(); - } - - try (InputStream fileStream = getObjectResponse.getInputStream()) { - byte[] objectContent = fileStream.readAllBytes(); - Response.ResponseBuilder ok = Response.ok(objectContent) - .header(HeaderNames.CONTENT_DISPOSITION.defaultCase(), "attachment; filename=\"" + fileName + "\"") - .header("opc-request-id", getObjectResponse.getOpcRequestId()) - .header("request-id", getObjectResponse.getOpcClientRequestId()) - .header(HeaderNames.CONTENT_LENGTH.defaultCase(), getObjectResponse.getContentLength()); - - return ok.build(); - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Error processing GetObjectResponse", e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); - } - } - - /** - * Upload a file to object storage. - * - * @param fileName name of the object - * @return response - */ - @POST - @Path("/file/{fileName}") - public Response upload(@PathParam("fileName") String fileName) { - - PutObjectRequest putObjectRequest = null; - try (InputStream stream = new FileInputStream(System.getProperty("user.dir") + File.separator + fileName)) { - byte[] contents = stream.readAllBytes(); - putObjectRequest = - PutObjectRequest.builder() - .namespaceName(namespaceName) - .bucketName(bucketName) - .objectName(fileName) - .putObjectBody(new ByteArrayInputStream(contents)) - .contentLength(Long.valueOf(contents.length)) - .build(); - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Error creating PutObjectRequest", e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); - } - PutObjectResponse putObjectResponse = objectStorageClient.putObject(putObjectRequest); - - Response.ResponseBuilder ok = Response.ok() - .header("opc-request-id", putObjectResponse.getOpcRequestId()) - .header("request-id", putObjectResponse.getOpcClientRequestId()); - - return ok.build(); - } - - /** - * Delete a file from object storage. - * - * @param fileName object name - * @return response - */ - @DELETE - @Path("/file/{file-name}") - public Response delete(@PathParam("file-name") String fileName) { - DeleteObjectResponse deleteObjectResponse = objectStorageClient.deleteObject(DeleteObjectRequest.builder() - .namespaceName(namespaceName) - .bucketName(bucketName) - .objectName(fileName) - .build()); - Response.ResponseBuilder ok = Response.ok() - .header("opc-request-id", deleteObjectResponse.getOpcRequestId()) - .header("request-id", deleteObjectResponse.getOpcClientRequestId()); - - return ok.build(); - } -} diff --git a/examples/integrations/oci/objectstorage-cdi/src/main/java/io/helidon/examples/integrations/oci/objectstorage/cdi/package-info.java b/examples/integrations/oci/objectstorage-cdi/src/main/java/io/helidon/examples/integrations/oci/objectstorage/cdi/package-info.java deleted file mode 100644 index d2e98404d0f..00000000000 --- a/examples/integrations/oci/objectstorage-cdi/src/main/java/io/helidon/examples/integrations/oci/objectstorage/cdi/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 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 of integration with OCI object storage in a CDI application. - */ -package io.helidon.examples.integrations.oci.objectstorage.cdi; diff --git a/examples/integrations/oci/objectstorage-cdi/src/main/resources/META-INF/beans.xml b/examples/integrations/oci/objectstorage-cdi/src/main/resources/META-INF/beans.xml deleted file mode 100644 index dbf3e648c1e..00000000000 --- a/examples/integrations/oci/objectstorage-cdi/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/integrations/oci/objectstorage-cdi/src/main/resources/application.yaml b/examples/integrations/oci/objectstorage-cdi/src/main/resources/application.yaml deleted file mode 100644 index f0b991ad95b..00000000000 --- a/examples/integrations/oci/objectstorage-cdi/src/main/resources/application.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2021, 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 - -# -# The following properties under oci are accessed by Helidon. Values -# under oci.properties.* are read from ~/helidon/conf/examples.yaml. -# -oci: - objectstorage: - bucketName: "${oci.properties.objectstorage-bucketName}" diff --git a/examples/integrations/oci/objectstorage-cdi/src/main/resources/logging.properties b/examples/integrations/oci/objectstorage-cdi/src/main/resources/logging.properties deleted file mode 100644 index b4eb284e666..00000000000 --- a/examples/integrations/oci/objectstorage-cdi/src/main/resources/logging.properties +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2021, 2023 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. -# - -# Send messages to the console -handlers=io.helidon.logging.jul.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 - -io.helidon.level=INFO -io.helidon.integrations.level=INFO -io.helidon.webclient.level=INFO diff --git a/examples/integrations/oci/objectstorage/README.md b/examples/integrations/oci/objectstorage/README.md deleted file mode 100644 index 06c5c52ba24..00000000000 --- a/examples/integrations/oci/objectstorage/README.md +++ /dev/null @@ -1,9 +0,0 @@ -The object storage example. - -The example requires OCI config in some default place like ``.oci/config`` - -Build and run the example by -```shell -mvn package -java -jar ./target/helidon-examples-integrations-oci-objectstorage.jar -``` diff --git a/examples/integrations/oci/objectstorage/pom.xml b/examples/integrations/oci/objectstorage/pom.xml deleted file mode 100644 index e6de12c28c9..00000000000 --- a/examples/integrations/oci/objectstorage/pom.xml +++ /dev/null @@ -1,73 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../../applications/se/pom.xml - - - io.helidon.examples.integrations.oci - helidon-examples-integrations-oci-objectstorage - Helidon Examples Integration OCI Object Storage - Integration with OCI Object Storage. - - - io.helidon.examples.integrations.oci.objecstorage.OciObjectStorageMain - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.config - helidon-config-yaml - - - com.oracle.oci.sdk - oci-java-sdk-objectstorage - - - com.oracle.oci.sdk - oci-java-sdk-common-httpclient-jersey3 - runtime - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/integrations/oci/objectstorage/src/main/java/io/helidon/examples/integrations/oci/objecstorage/ObjectStorageService.java b/examples/integrations/oci/objectstorage/src/main/java/io/helidon/examples/integrations/oci/objecstorage/ObjectStorageService.java deleted file mode 100644 index 9d45a77b5cb..00000000000 --- a/examples/integrations/oci/objectstorage/src/main/java/io/helidon/examples/integrations/oci/objecstorage/ObjectStorageService.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.oci.objecstorage; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.helidon.config.Config; -import io.helidon.config.ConfigException; -import io.helidon.http.HeaderNames; -import io.helidon.http.Status; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -import com.oracle.bmc.ConfigFileReader; -import com.oracle.bmc.auth.AuthenticationDetailsProvider; -import com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider; -import com.oracle.bmc.objectstorage.ObjectStorage; -import com.oracle.bmc.objectstorage.ObjectStorageClient; -import com.oracle.bmc.objectstorage.requests.DeleteObjectRequest; -import com.oracle.bmc.objectstorage.requests.GetNamespaceRequest; -import com.oracle.bmc.objectstorage.requests.GetObjectRequest; -import com.oracle.bmc.objectstorage.requests.PutObjectRequest; -import com.oracle.bmc.objectstorage.responses.DeleteObjectResponse; -import com.oracle.bmc.objectstorage.responses.GetNamespaceResponse; -import com.oracle.bmc.objectstorage.responses.GetObjectResponse; -import com.oracle.bmc.objectstorage.responses.PutObjectResponse; - -/** - * REST API for the objecstorage example. - */ -public class ObjectStorageService implements HttpService { - private static final Logger LOGGER = Logger.getLogger(ObjectStorageService.class.getName()); - private final ObjectStorage objectStorageClient; - private final String namespaceName; - private final String bucketName; - - - ObjectStorageService(Config config) { - try { - ConfigFileReader.ConfigFile configFile = ConfigFileReader.parseDefault(); - AuthenticationDetailsProvider authProvider = new ConfigFileAuthenticationDetailsProvider(configFile); - this.objectStorageClient = ObjectStorageClient.builder().build(authProvider); - this.bucketName = config.get("oci.objectstorage.bucketName") - .asString() - .orElseThrow(() -> new IllegalStateException("Missing bucket name!!")); - GetNamespaceResponse namespaceResponse = - this.objectStorageClient.getNamespace(GetNamespaceRequest.builder().build()); - this.namespaceName = namespaceResponse.getValue(); - } catch (IOException e) { - throw new ConfigException("Failed to read configuration properties", e); - } - } - - /** - * A service registers itself by updating the routine rules. - * - * @param rules the routing rules. - */ - public void routing(HttpRules rules) { - rules.get("/file/{file-name}", this::download); - rules.post("/file/{fileName}", this::upload); - rules.delete("/file/{file-name}", this::delete); - } - - /** - * Download a file from object storage. - * - * @param request request - * @param response response - */ - public void download(ServerRequest request, ServerResponse response) { - String fileName = request.path().pathParameters().get("file-name"); - GetObjectResponse getObjectResponse = - objectStorageClient.getObject( - GetObjectRequest.builder() - .namespaceName(namespaceName) - .bucketName(bucketName) - .objectName(fileName) - .build()); - - if (getObjectResponse.getContentLength() == 0) { - LOGGER.log(Level.SEVERE, "GetObjectResponse is empty"); - response.status(Status.NOT_FOUND_404).send(); - return; - } - - try (InputStream fileStream = getObjectResponse.getInputStream()) { - byte[] objectContent = fileStream.readAllBytes(); - response - .status(Status.OK_200) - .header(HeaderNames.CONTENT_DISPOSITION.defaultCase(), "attachment; filename=\"" + fileName + "\"") - .header("opc-request-id", getObjectResponse.getOpcRequestId()) - .header(HeaderNames.CONTENT_LENGTH.defaultCase(), getObjectResponse.getContentLength().toString()); - - response.send(objectContent); - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Error processing GetObjectResponse", e); - response.status(Status.INTERNAL_SERVER_ERROR_500).send(); - } - } - - /** - * Upload a file to object storage. - * - * @param request request - * @param response response - */ - public void upload(ServerRequest request, ServerResponse response) { - String fileName = request.path().pathParameters().get("fileName"); - PutObjectRequest putObjectRequest; - try (InputStream stream = new FileInputStream(System.getProperty("user.dir") + File.separator + fileName)) { - byte[] contents = stream.readAllBytes(); - putObjectRequest = - PutObjectRequest.builder() - .namespaceName(namespaceName) - .bucketName(bucketName) - .objectName(fileName) - .putObjectBody(new ByteArrayInputStream(contents)) - .contentLength((long) contents.length) - .build(); - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Error creating PutObjectRequest", e); - response.status(Status.INTERNAL_SERVER_ERROR_500).send(); - return; - } - PutObjectResponse putObjectResponse = objectStorageClient.putObject(putObjectRequest); - - response.status(Status.OK_200).header("opc-request-id", putObjectResponse.getOpcRequestId()); - - response.send(); - } - - /** - * Delete a file from object storage. - * - * @param request request - * @param response response - */ - public void delete(ServerRequest request, ServerResponse response) { - String fileName = request.path().pathParameters().get("file-name"); - DeleteObjectResponse deleteObjectResponse = objectStorageClient.deleteObject(DeleteObjectRequest.builder() - .namespaceName(namespaceName) - .bucketName(bucketName) - .objectName(fileName) - .build()); - response.status(Status.OK_200).header("opc-request-id", deleteObjectResponse.getOpcRequestId()); - - response.send(); - } -} diff --git a/examples/integrations/oci/objectstorage/src/main/java/io/helidon/examples/integrations/oci/objecstorage/OciObjectStorageMain.java b/examples/integrations/oci/objectstorage/src/main/java/io/helidon/examples/integrations/oci/objecstorage/OciObjectStorageMain.java deleted file mode 100644 index 5df3f1d19d9..00000000000 --- a/examples/integrations/oci/objectstorage/src/main/java/io/helidon/examples/integrations/oci/objecstorage/OciObjectStorageMain.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.oci.objecstorage; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; -import java.util.function.Supplier; - -import io.helidon.config.Config; -import io.helidon.config.spi.ConfigSource; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.http.HttpRouting; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.file; - -/** - * Main class of the example. - * This example sets up a web server to serve REST API to upload/download/delete objects. - */ -public final class OciObjectStorageMain { - - private OciObjectStorageMain() { - } - - /** - * Main method. - * - * @param args ignored - */ - public static void main(String[] args) { - Config config = Config - .builder() - .sources(examplesConfig()) - .build(); - WebServer.builder() - .routing(r -> routing(r, config)) - .config(config.get("server")) - .build() - .start(); - } - - /** - * Updates HTTP Routing. - * - * @param routing routing builder - * @param config config - */ - static void routing(HttpRouting.Builder routing, Config config) { - ObjectStorageService objectStorageService = new ObjectStorageService(config); - routing.register("/files", objectStorageService); - } - - private static List> examplesConfig() { - List> suppliers = new ArrayList<>(); - Path path = Paths.get(System.getProperty("user.home") + "/helidon/conf/examples.yaml"); - if (Files.exists(path)) { - suppliers.add(file(path).build()); - } - suppliers.add(classpath("application.yaml").build()); - return suppliers; - } -} diff --git a/examples/integrations/oci/objectstorage/src/main/java/io/helidon/examples/integrations/oci/objecstorage/package-info.java b/examples/integrations/oci/objectstorage/src/main/java/io/helidon/examples/integrations/oci/objecstorage/package-info.java deleted file mode 100644 index ac79e32f44f..00000000000 --- a/examples/integrations/oci/objectstorage/src/main/java/io/helidon/examples/integrations/oci/objecstorage/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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 of integration with OCI object storage in a Helidon SE application. - */ -package io.helidon.examples.integrations.oci.objecstorage; diff --git a/examples/integrations/oci/objectstorage/src/main/resources/application.yaml b/examples/integrations/oci/objectstorage/src/main/resources/application.yaml deleted file mode 100644 index 75e202bd486..00000000000 --- a/examples/integrations/oci/objectstorage/src/main/resources/application.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2021, 2023 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. -# - -# The values are read from -# ~/helidon/conf/examples.yaml -# or you can just update them here - -server: - port: 8080 - -oci: - objectstorage: - bucketName: "${oci.properties.objectstorage-bucketName}" diff --git a/examples/integrations/oci/objectstorage/src/main/resources/logging.properties b/examples/integrations/oci/objectstorage/src/main/resources/logging.properties deleted file mode 100644 index b4eb284e666..00000000000 --- a/examples/integrations/oci/objectstorage/src/main/resources/logging.properties +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2021, 2023 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. -# - -# Send messages to the console -handlers=io.helidon.logging.jul.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 - -io.helidon.level=INFO -io.helidon.integrations.level=INFO -io.helidon.webclient.level=INFO diff --git a/examples/integrations/oci/pom.xml b/examples/integrations/oci/pom.xml deleted file mode 100644 index abb77995f2f..00000000000 --- a/examples/integrations/oci/pom.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - 4.0.0 - - io.helidon.examples.integrations - helidon-examples-integrations-project - 4.1.0-SNAPSHOT - - io.helidon.examples.integrations.oci - helidon-examples-integrations-oci-project - pom - Helidon Examples Integration OCI - Examples of integration with OCI (Oracle Cloud). - - - atp - atp-cdi - metrics - objectstorage - objectstorage-cdi - vault - vault-cdi - - - diff --git a/examples/integrations/oci/vault-cdi/README.md b/examples/integrations/oci/vault-cdi/README.md deleted file mode 100644 index aba4193e192..00000000000 --- a/examples/integrations/oci/vault-cdi/README.md +++ /dev/null @@ -1,12 +0,0 @@ -The vault (CDI) example. - -The example requires OCI config in some default place like ``.oci/config`` - -Also properties from the ``src/main/resources/application.yaml`` shall be configured. -Like ``oci.properties.compartment-ocid`` - -Build and run the example by -```shell -mvn package -java -jar ./target/helidon-examples-integrations-oci-vault-cdi.jar -``` \ No newline at end of file diff --git a/examples/integrations/oci/vault-cdi/pom.xml b/examples/integrations/oci/vault-cdi/pom.xml deleted file mode 100644 index 7c89bf85a76..00000000000 --- a/examples/integrations/oci/vault-cdi/pom.xml +++ /dev/null @@ -1,101 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../../applications/mp/pom.xml - - - io.helidon.examples.integrations.oci - helidon-examples-integrations-oci-vault-cdi - Helidon Examples Integration OCI Object Storage CDI - CDI integration with OCI Object Storage. - - - io.helidon.examples.integrations.oci.vault.cdi.VaultCdiMain - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.integrations.oci.sdk - helidon-integrations-oci-sdk-cdi - - - com.oracle.oci.sdk - oci-java-sdk-keymanagement - - - com.oracle.oci.sdk - oci-java-sdk-secrets - - - com.oracle.oci.sdk - oci-java-sdk-vault - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.microprofile.testing - helidon-microprofile-testing-junit5 - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - - diff --git a/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/CryptoClientProducer.java b/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/CryptoClientProducer.java deleted file mode 100644 index 5050eb59b09..00000000000 --- a/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/CryptoClientProducer.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.integrations.oci.vault.cdi; - -import com.oracle.bmc.keymanagement.KmsCryptoClient; -import com.oracle.bmc.keymanagement.KmsCryptoClientBuilder; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.Produces; -import jakarta.inject.Inject; -import org.eclipse.microprofile.config.inject.ConfigProperty; - -/** - * KMS crypto client (used for encryption, decryption and signatures) requires additional configuration, that cannot - * be done automatically by the SDK. - */ -@ApplicationScoped -class CryptoClientProducer { - private final String cryptoEndpoint; - - @Inject - CryptoClientProducer(@ConfigProperty(name = "app.vault.cryptographic-endpoint") - String cryptoEndpoint) { - this.cryptoEndpoint = cryptoEndpoint; - } - - @Produces - KmsCryptoClientBuilder clientBuilder() { - return KmsCryptoClient.builder() - .endpoint(cryptoEndpoint); - } -} diff --git a/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/ErrorHandlerProvider.java b/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/ErrorHandlerProvider.java deleted file mode 100644 index a6b67e6ff22..00000000000 --- a/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/ErrorHandlerProvider.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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.integrations.oci.vault.cdi; - -import com.oracle.bmc.model.BmcException; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.ext.ExceptionMapper; -import jakarta.ws.rs.ext.Provider; - -/** - * Maps SDK errors to HTTP errors, as otherwise any exception is manifested as an internal server error. - * This mapper is not part of integration with OCI SDK, as each application may require a different entity format. - * This mapper simply uses the response code as HTTP status code, and error message as entity. - */ -@Provider -class ErrorHandlerProvider implements ExceptionMapper { - @Override - public Response toResponse(BmcException e) { - return Response.status(e.getStatusCode()) - .entity(e.getMessage()) - .build(); - } -} diff --git a/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/VaultCdiMain.java b/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/VaultCdiMain.java deleted file mode 100644 index ce92665f14e..00000000000 --- a/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/VaultCdiMain.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2021 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.integrations.oci.vault.cdi; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; - -import io.helidon.config.yaml.mp.YamlMpConfigSource; -import io.helidon.microprofile.cdi.Main; - -import org.eclipse.microprofile.config.Config; -import org.eclipse.microprofile.config.spi.ConfigProviderResolver; -import org.eclipse.microprofile.config.spi.ConfigSource; - -/** - * Main class of the example. - * Used only to set up configuration. - */ -public final class VaultCdiMain { - private VaultCdiMain() { - } - - /** - * Main method. - * - * @param args ignored - */ - public static void main(String[] args) { - ConfigProviderResolver configProvider = ConfigProviderResolver.instance(); - - Config mpConfig = configProvider.getBuilder() - .addDefaultSources() - .withSources(examplesConfig()) - .addDiscoveredSources() - .addDiscoveredConverters() - .build(); - - // configure - configProvider.registerConfig(mpConfig, null); - - // start CDI - Main.main(args); - } - - private static ConfigSource[] examplesConfig() { - Path path = Paths.get(System.getProperty("user.home") + "/helidon/conf/examples.yaml"); - if (Files.exists(path)) { - return new ConfigSource[] {YamlMpConfigSource.create(path)}; - } - return new ConfigSource[0]; - } -} diff --git a/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/VaultResource.java b/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/VaultResource.java deleted file mode 100644 index fdeac30e50b..00000000000 --- a/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/VaultResource.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright (c) 2021, 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.integrations.oci.vault.cdi; - -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import java.util.Date; - -import io.helidon.common.Base64Value; - -import com.oracle.bmc.keymanagement.KmsCrypto; -import com.oracle.bmc.keymanagement.model.DecryptDataDetails; -import com.oracle.bmc.keymanagement.model.EncryptDataDetails; -import com.oracle.bmc.keymanagement.model.SignDataDetails; -import com.oracle.bmc.keymanagement.model.VerifyDataDetails; -import com.oracle.bmc.keymanagement.requests.DecryptRequest; -import com.oracle.bmc.keymanagement.requests.EncryptRequest; -import com.oracle.bmc.keymanagement.requests.SignRequest; -import com.oracle.bmc.keymanagement.requests.VerifyRequest; -import com.oracle.bmc.secrets.Secrets; -import com.oracle.bmc.secrets.model.Base64SecretBundleContentDetails; -import com.oracle.bmc.secrets.model.SecretBundleContentDetails; -import com.oracle.bmc.secrets.requests.GetSecretBundleRequest; -import com.oracle.bmc.vault.Vaults; -import com.oracle.bmc.vault.model.Base64SecretContentDetails; -import com.oracle.bmc.vault.model.CreateSecretDetails; -import com.oracle.bmc.vault.model.ScheduleSecretDeletionDetails; -import com.oracle.bmc.vault.model.SecretContentDetails; -import com.oracle.bmc.vault.requests.CreateSecretRequest; -import com.oracle.bmc.vault.requests.ScheduleSecretDeletionRequest; -import jakarta.inject.Inject; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.InternalServerErrorException; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import org.eclipse.microprofile.config.inject.ConfigProperty; - -/** - * JAX-RS resource - REST API of the example. - */ -@Path("/vault") -public class VaultResource { - private final Secrets secrets; - private final KmsCrypto crypto; - private final Vaults vaults; - private final String vaultOcid; - private final String compartmentOcid; - private final String encryptionKeyOcid; - private final String signatureKeyOcid; - - @Inject - VaultResource(Secrets secrets, - KmsCrypto crypto, - Vaults vaults, - @ConfigProperty(name = "app.vault.vault-ocid") - String vaultOcid, - @ConfigProperty(name = "app.vault.compartment-ocid") - String compartmentOcid, - @ConfigProperty(name = "app.vault.encryption-key-ocid") - String encryptionKeyOcid, - @ConfigProperty(name = "app.vault.signature-key-ocid") - String signatureKeyOcid) { - this.secrets = secrets; - this.crypto = crypto; - this.vaults = vaults; - this.vaultOcid = vaultOcid; - this.compartmentOcid = compartmentOcid; - this.encryptionKeyOcid = encryptionKeyOcid; - this.signatureKeyOcid = signatureKeyOcid; - } - - /** - * Encrypt a string. - * - * @param secret secret to encrypt - * @return cipher text - */ - @GET - @Path("/encrypt/{text}") - public String encrypt(@PathParam("text") String secret) { - return crypto.encrypt(EncryptRequest.builder() - .encryptDataDetails(EncryptDataDetails.builder() - .keyId(encryptionKeyOcid) - .plaintext(Base64Value.create(secret).toBase64()) - .build()) - .build()) - .getEncryptedData() - .getCiphertext(); - } - - /** - * Decrypt a cipher text. - * - * @param cipherText cipher text to decrypt - * @return original secret - */ - @GET - @Path("/decrypt/{text: .*}") - public String decrypt(@PathParam("text") String cipherText) { - return Base64Value.createFromEncoded(crypto.decrypt(DecryptRequest.builder() - .decryptDataDetails(DecryptDataDetails.builder() - .keyId(encryptionKeyOcid) - .ciphertext(cipherText) - .build()) - .build()) - .getDecryptedData() - .getPlaintext()) - .toDecodedString(); - } - - /** - * Sign data. - * - * @param dataToSign data to sign (must be a String) - * @return signature text - */ - @GET - @Path("/sign/{text}") - public String sign(@PathParam("text") String dataToSign) { - return crypto.sign(SignRequest.builder() - .signDataDetails(SignDataDetails.builder() - .keyId(signatureKeyOcid) - .signingAlgorithm(SignDataDetails.SigningAlgorithm.Sha224RsaPkcsPss) - .message(Base64Value.create(dataToSign).toBase64()) - .build()) - .build()) - .getSignedData() - .getSignature(); - } - - /** - * Verify a signature. The base64 encoded signature is the entity - * - * @param dataToVerify data that was signed - * @param signature signature text - * @return whether the signature is valid or not - */ - @POST - @Path("/verify/{text}") - public String verify(@PathParam("text") String dataToVerify, - String signature) { - VerifyDataDetails.SigningAlgorithm algorithm = VerifyDataDetails.SigningAlgorithm.Sha224RsaPkcsPss; - - boolean valid = crypto.verify(VerifyRequest.builder() - .verifyDataDetails(VerifyDataDetails.builder() - .keyId(signatureKeyOcid) - .signingAlgorithm(algorithm) - .message(Base64Value.create(dataToVerify).toBase64()) - .signature(signature) - .build()) - .build()) - .getVerifiedData() - .getIsSignatureValid(); - - return valid ? "Signature valid" : "Signature not valid"; - } - - /** - * Get secret content from Vault. - * - * @param secretOcid OCID of the secret to get - * @return content of the secret - */ - @GET - @Path("/secret/{id}") - public String getSecret(@PathParam("id") String secretOcid) { - SecretBundleContentDetails content = secrets.getSecretBundle(GetSecretBundleRequest.builder() - .secretId(secretOcid) - .build()) - .getSecretBundle() - .getSecretBundleContent(); - - if (content instanceof Base64SecretBundleContentDetails) { - // the only supported type - return Base64Value.createFromEncoded(((Base64SecretBundleContentDetails) content).getContent()).toDecodedString(); - } else { - throw new InternalServerErrorException("Invalid secret content type"); - } - } - - /** - * Delete a secret from Vault. - * This operation actually marks a secret for deletion, and the minimal time is 30 days. - * - * @param secretOcid OCID of the secret to delete - * @return short message - */ - @DELETE - @Path("/secret/{id}") - public String deleteSecret(@PathParam("id") String secretOcid) { - // has to be for quite a long period of time - did not work with less than 30 days - Date deleteTime = Date.from(Instant.now().plus(30, ChronoUnit.DAYS)); - - vaults.scheduleSecretDeletion(ScheduleSecretDeletionRequest.builder() - .secretId(secretOcid) - .scheduleSecretDeletionDetails(ScheduleSecretDeletionDetails.builder() - .timeOfDeletion(deleteTime) - .build()) - .build()); - - return "Secret " + secretOcid + " was marked for deletion"; - } - - /** - * Create a new secret. - * - * @param name name of the secret - * @param secretText secret content - * @return OCID of the created secret - */ - @POST - @Path("/secret/{name}") - public String createSecret(@PathParam("name") String name, - String secretText) { - SecretContentDetails content = Base64SecretContentDetails.builder() - .content(Base64Value.create(secretText).toBase64()) - .build(); - - return vaults.createSecret(CreateSecretRequest.builder() - .createSecretDetails(CreateSecretDetails.builder() - .secretName(name) - .vaultId(vaultOcid) - .compartmentId(compartmentOcid) - .keyId(encryptionKeyOcid) - .secretContent(content) - .build()) - .build()) - .getSecret() - .getId(); - } -} diff --git a/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/package-info.java b/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/package-info.java deleted file mode 100644 index 80a511eaad0..00000000000 --- a/examples/integrations/oci/vault-cdi/src/main/java/io/helidon/examples/integrations/oci/vault/cdi/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 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 of OCI Vault integration in CDI. - */ -package io.helidon.examples.integrations.oci.vault.cdi; diff --git a/examples/integrations/oci/vault-cdi/src/main/resources/META-INF/beans.xml b/examples/integrations/oci/vault-cdi/src/main/resources/META-INF/beans.xml deleted file mode 100644 index dbf3e648c1e..00000000000 --- a/examples/integrations/oci/vault-cdi/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/integrations/oci/vault-cdi/src/main/resources/application.yaml b/examples/integrations/oci/vault-cdi/src/main/resources/application.yaml deleted file mode 100644 index 3ea5b75de39..00000000000 --- a/examples/integrations/oci/vault-cdi/src/main/resources/application.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# -# Copyright (c) 2021, 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 - -# -# The following properties under oci are accessed by Helidon. Values -# under oci.properties.* are read from ~/helidon/conf/examples.yaml. -# -app: - vault: - # Vault OCID (the vault you want to use for this example) - vault-ocid: "${oci.properties.vault-ocid}" - compartment-ocid: "${oci.properties.compartment-ocid}" - encryption-key-ocid: "${oci.properties.vault-key-ocid}" - signature-key-ocid: "${oci.properties.vault-rsa-key-ocid}" - cryptographic-endpoint: "${oci.properties.cryptographic-endpoint}" diff --git a/examples/integrations/oci/vault-cdi/src/main/resources/logging.properties b/examples/integrations/oci/vault-cdi/src/main/resources/logging.properties deleted file mode 100644 index f8802f90626..00000000000 --- a/examples/integrations/oci/vault-cdi/src/main/resources/logging.properties +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright (c) 2021, 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. -# - -# Send messages to the console -handlers=io.helidon.logging.jul.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 - -io.helidon.level=INFO -io.helidon.integrations.level=INFO diff --git a/examples/integrations/oci/vault/README.md b/examples/integrations/oci/vault/README.md deleted file mode 100644 index 42fa855114d..00000000000 --- a/examples/integrations/oci/vault/README.md +++ /dev/null @@ -1,9 +0,0 @@ -The vault example. - -The example requires OCI config in some default place like ``.oci/config`` - -Build and run the example by -```shell -mvn package -java -jar ./target/helidon-examples-integrations-oci-vault.jar -``` diff --git a/examples/integrations/oci/vault/pom.xml b/examples/integrations/oci/vault/pom.xml deleted file mode 100644 index ef97c7aa19f..00000000000 --- a/examples/integrations/oci/vault/pom.xml +++ /dev/null @@ -1,82 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../../applications/se/pom.xml - - - io.helidon.examples.integrations.oci - helidon-examples-integrations-oci-vault - Helidon Examples Integration OCI Vault - Integration with OCI Vault. - - - io.helidon.examples.integrations.oci.vault.OciVaultMain - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.config - helidon-config-yaml - - - com.oracle.oci.sdk - oci-java-sdk-keymanagement - - - com.oracle.oci.sdk - oci-java-sdk-secrets - - - com.oracle.oci.sdk - oci-java-sdk-vault - - - com.oracle.oci.sdk - oci-java-sdk-common-httpclient-jersey3 - runtime - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - - diff --git a/examples/integrations/oci/vault/src/main/java/io/helidon/examples/integrations/oci/vault/OciVaultMain.java b/examples/integrations/oci/vault/src/main/java/io/helidon/examples/integrations/oci/vault/OciVaultMain.java deleted file mode 100644 index 8185f5c6aaa..00000000000 --- a/examples/integrations/oci/vault/src/main/java/io/helidon/examples/integrations/oci/vault/OciVaultMain.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.oci.vault; - -import java.io.IOException; - -import io.helidon.config.Config; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; - -import com.oracle.bmc.ConfigFileReader; -import com.oracle.bmc.auth.AuthenticationDetailsProvider; -import com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider; -import com.oracle.bmc.keymanagement.KmsCrypto; -import com.oracle.bmc.keymanagement.KmsCryptoClient; -import com.oracle.bmc.model.BmcException; -import com.oracle.bmc.secrets.Secrets; -import com.oracle.bmc.secrets.SecretsClient; -import com.oracle.bmc.vault.Vaults; -import com.oracle.bmc.vault.VaultsClient; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.file; - -/** - * Main class of the example. - * Boots a web server and provides REST API for Vault interactions. - */ -public final class OciVaultMain { - private OciVaultMain() { - } - - /** - * Main method. - * @param args ignored - */ - public static void main(String[] args) throws IOException { - LogConfig.configureRuntime(); - - // as I cannot share my configuration of OCI, let's combine the configuration - // from my home directory with the one compiled into the jar - // when running this example, you can either update the application.yaml in resources directory - // or use the same approach - Config config = buildConfig(); - - Config vaultConfig = config.get("oci.vault"); - // the following three parameters are required - String vaultOcid = vaultConfig.get("vault-ocid").asString().get(); - String compartmentOcid = vaultConfig.get("compartment-ocid").asString().get(); - String encryptionKey = vaultConfig.get("encryption-key-ocid").asString().get(); - String signatureKey = vaultConfig.get("signature-key-ocid").asString().get(); - String cryptoEndpoint = vaultConfig.get("cryptographic-endpoint").asString().get(); - - // this requires OCI configuration in the usual place - // ~/.oci/config - AuthenticationDetailsProvider authProvider = new ConfigFileAuthenticationDetailsProvider(ConfigFileReader.parseDefault()); - - Secrets secrets = SecretsClient.builder().build(authProvider); - KmsCrypto crypto = KmsCryptoClient.builder() - .endpoint(cryptoEndpoint) - .build(authProvider); - Vaults vaults = VaultsClient.builder().build(authProvider); - - WebServer server = WebServer.builder() - .routing(routing -> routing - .register("/vault", new VaultService(secrets, - vaults, - crypto, - vaultOcid, - compartmentOcid, - encryptionKey, - signatureKey)) - .error(BmcException.class, (req, res, ex) -> res.status( - ex.getStatusCode()).send(ex.getMessage()))) - .config(config.get("server")) - .build() - .start(); - - System.out.println("WEB server is up! http://localhost:" + server.port()); - - } - - private static Config buildConfig() { - return Config.builder() - .sources( - // you can use this file to override the defaults that are built-in - file(System.getProperty("user.home") + "/helidon/conf/examples.yaml").optional(), - // in jar file (see src/main/resources/application.yaml) - classpath("application.yaml")) - .build(); - } -} diff --git a/examples/integrations/oci/vault/src/main/java/io/helidon/examples/integrations/oci/vault/VaultService.java b/examples/integrations/oci/vault/src/main/java/io/helidon/examples/integrations/oci/vault/VaultService.java deleted file mode 100644 index 4a017270212..00000000000 --- a/examples/integrations/oci/vault/src/main/java/io/helidon/examples/integrations/oci/vault/VaultService.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.oci.vault; - -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import java.util.Date; -import java.util.function.Consumer; -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.helidon.common.Base64Value; -import io.helidon.http.Status; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -import com.oracle.bmc.keymanagement.KmsCrypto; -import com.oracle.bmc.keymanagement.model.DecryptDataDetails; -import com.oracle.bmc.keymanagement.model.EncryptDataDetails; -import com.oracle.bmc.keymanagement.model.SignDataDetails; -import com.oracle.bmc.keymanagement.model.VerifyDataDetails; -import com.oracle.bmc.keymanagement.requests.DecryptRequest; -import com.oracle.bmc.keymanagement.requests.EncryptRequest; -import com.oracle.bmc.keymanagement.requests.SignRequest; -import com.oracle.bmc.keymanagement.requests.VerifyRequest; -import com.oracle.bmc.keymanagement.responses.DecryptResponse; -import com.oracle.bmc.keymanagement.responses.EncryptResponse; -import com.oracle.bmc.keymanagement.responses.SignResponse; -import com.oracle.bmc.keymanagement.responses.VerifyResponse; -import com.oracle.bmc.secrets.Secrets; -import com.oracle.bmc.secrets.model.Base64SecretBundleContentDetails; -import com.oracle.bmc.secrets.model.SecretBundleContentDetails; -import com.oracle.bmc.secrets.requests.GetSecretBundleRequest; -import com.oracle.bmc.secrets.responses.GetSecretBundleResponse; -import com.oracle.bmc.vault.Vaults; -import com.oracle.bmc.vault.model.Base64SecretContentDetails; -import com.oracle.bmc.vault.model.CreateSecretDetails; -import com.oracle.bmc.vault.model.ScheduleSecretDeletionDetails; -import com.oracle.bmc.vault.model.SecretContentDetails; -import com.oracle.bmc.vault.requests.CreateSecretRequest; -import com.oracle.bmc.vault.requests.ScheduleSecretDeletionRequest; -import com.oracle.bmc.vault.responses.CreateSecretResponse; - -class VaultService implements HttpService { - - private static final Logger LOGGER = Logger.getLogger(VaultService.class.getName()); - private final Secrets secrets; - private final Vaults vaults; - private final KmsCrypto crypto; - private final String vaultOcid; - private final String compartmentOcid; - private final String encryptionKeyOcid; - private final String signatureKeyOcid; - - VaultService(Secrets secrets, - Vaults vaults, - KmsCrypto crypto, - String vaultOcid, - String compartmentOcid, - String encryptionKeyOcid, - String signatureKeyOcid) { - this.secrets = secrets; - this.vaults = vaults; - this.crypto = crypto; - this.vaultOcid = vaultOcid; - this.compartmentOcid = compartmentOcid; - this.encryptionKeyOcid = encryptionKeyOcid; - this.signatureKeyOcid = signatureKeyOcid; - } - - /** - * A service registers itself by updating the routine rules. - * - * @param rules the routing rules. - */ - @Override - public void routing(HttpRules rules) { - rules.get("/encrypt/{text:.*}", this::encrypt) - .get("/decrypt/{text:.*}", this::decrypt) - .get("/sign/{text}", this::sign) - .post("/verify/{text}", this::verify) - .get("/secret/{id}", this::getSecret) - .post("/secret/{name}", this::createSecret) - .delete("/secret/{id}", this::deleteSecret); - } - - private void getSecret(ServerRequest req, ServerResponse res) { - ociHandler(response -> { - GetSecretBundleResponse id = secrets.getSecretBundle(GetSecretBundleRequest.builder() - .secretId(req.path().pathParameters().get("id")) - .build()); - SecretBundleContentDetails content = id.getSecretBundle().getSecretBundleContent(); - if (content instanceof Base64SecretBundleContentDetails) { - // the only supported type - res.send(Base64Value.createFromEncoded(((Base64SecretBundleContentDetails) content).getContent()) - .toDecodedString()); - } else { - res.status(Status.INTERNAL_SERVER_ERROR_500).send("Invalid secret content type"); - } - }, res); - - } - - private void deleteSecret(ServerRequest req, ServerResponse res) { - ociHandler(response -> { - // has to be for quite a long period of time - did not work with less than 30 days - Date deleteTime = Date.from(Instant.now().plus(30, ChronoUnit.DAYS)); - String secretOcid = req.path().pathParameters().get("id"); - vaults.scheduleSecretDeletion(ScheduleSecretDeletionRequest.builder() - .secretId(secretOcid) - .scheduleSecretDeletionDetails(ScheduleSecretDeletionDetails.builder() - .timeOfDeletion(deleteTime) - .build()) - .build() - ); - response.send(String.format("Secret %s was marked for deletion", secretOcid)); - }, res); - } - - private void createSecret(ServerRequest req, ServerResponse res) { - ociHandler(response -> { - String secretText = req.content().as(String.class); - SecretContentDetails content = Base64SecretContentDetails.builder() - .content(Base64Value.create(secretText).toBase64()) - .build(); - CreateSecretResponse vaultsSecret = vaults.createSecret(CreateSecretRequest.builder() - .createSecretDetails(CreateSecretDetails.builder() - .secretName(req.path().pathParameters().get("name")) - .vaultId(vaultOcid) - .compartmentId(compartmentOcid) - .keyId(encryptionKeyOcid) - .secretContent(content) - .build()) - .build()); - response.send(vaultsSecret.getSecret().getId()); - }, res); - } - - private void verify(ServerRequest req, ServerResponse res) { - - - ociHandler(response -> { - String text = req.path().pathParameters().get("text"); - String signature = req.content().as(String.class); - VerifyDataDetails.SigningAlgorithm algorithm = VerifyDataDetails.SigningAlgorithm.Sha224RsaPkcsPss; - VerifyResponse verifyResponse = crypto.verify(VerifyRequest.builder() - .verifyDataDetails(VerifyDataDetails.builder() - .keyId(signatureKeyOcid) - .signingAlgorithm(algorithm) - .message(Base64Value.create(text).toBase64()) - .signature(signature) - .build()) - .build()); - boolean valid = verifyResponse.getVerifiedData().getIsSignatureValid(); - response.send(valid ? "Signature valid" : "Signature not valid"); - }, res); - } - - private void sign(ServerRequest req, ServerResponse res) { - ociHandler(response -> { - SignResponse signResponse = crypto.sign(SignRequest.builder() - .signDataDetails(SignDataDetails.builder() - .keyId(signatureKeyOcid) - .signingAlgorithm(SignDataDetails.SigningAlgorithm.Sha224RsaPkcsPss) - .message(Base64Value.create(req.path() - .pathParameters().get("text")).toBase64()) - .build()) - .build()); - response.send(signResponse.getSignedData().getSignature()); - }, res); - } - - private void encrypt(ServerRequest req, ServerResponse res) { - ociHandler(response -> { - EncryptResponse encryptResponse = crypto.encrypt(EncryptRequest.builder() - .encryptDataDetails(EncryptDataDetails.builder() - .keyId(encryptionKeyOcid) - .plaintext(Base64Value.create(req.path() - .pathParameters().get("text")).toBase64()) - .build()) - .build()); - response.send(encryptResponse.getEncryptedData().getCiphertext()); - }, res); - } - - private void decrypt(ServerRequest req, ServerResponse res) { - ociHandler(response -> { - DecryptResponse decryptResponse = crypto.decrypt(DecryptRequest.builder() - .decryptDataDetails(DecryptDataDetails.builder() - .keyId(encryptionKeyOcid) - .ciphertext(req.path() - .pathParameters().get("text")) - .build()) - .build()); - response.send(Base64Value.createFromEncoded(decryptResponse.getDecryptedData().getPlaintext()) - .toDecodedString()); - }, res); - } - - private void ociHandler(Consumer consumer, ServerResponse response) { - try { - consumer.accept(response); - } catch (Throwable error) { - LOGGER.log(Level.WARNING, "OCI Exception", error); - response.status(Status.INTERNAL_SERVER_ERROR_500).send(error.getMessage()); - } - } -} diff --git a/examples/integrations/oci/vault/src/main/java/io/helidon/examples/integrations/oci/vault/package-info.java b/examples/integrations/oci/vault/src/main/java/io/helidon/examples/integrations/oci/vault/package-info.java deleted file mode 100644 index 82d96ad4736..00000000000 --- a/examples/integrations/oci/vault/src/main/java/io/helidon/examples/integrations/oci/vault/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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 of OCI Vault integration in a SE application. - */ -package io.helidon.examples.integrations.oci.vault; diff --git a/examples/integrations/oci/vault/src/main/resources/application.yaml b/examples/integrations/oci/vault/src/main/resources/application.yaml deleted file mode 100644 index a61582e97b5..00000000000 --- a/examples/integrations/oci/vault/src/main/resources/application.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# -# Copyright (c) 2021, 2023 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 - -# -# The following properties under oci are accessed by Helidon. Values -# under oci.properties.* are read from ~/helidon/conf/examples.yaml. -# -oci: - vault: - # Vault OCID (the vault you want to use for this example - vault-ocid: "${oci.properties.vault-ocid}" - compartment-ocid: "${oci.properties.compartment-ocid}" - encryption-key-ocid: "${oci.properties.vault-key-ocid}" - signature-key-ocid: "${oci.properties.vault-rsa-key-ocid}" - cryptographic-endpoint: "${oci.properties.cryptographic-endpoint}" diff --git a/examples/integrations/oci/vault/src/main/resources/logging.properties b/examples/integrations/oci/vault/src/main/resources/logging.properties deleted file mode 100644 index 341cef8ce9e..00000000000 --- a/examples/integrations/oci/vault/src/main/resources/logging.properties +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright (c) 2021, 2023 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. -# - -# Send messages to the console -handlers=io.helidon.logging.jul.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 - -io.helidon.level=INFO -io.helidon.integrations.level=INFO diff --git a/examples/integrations/pom.xml b/examples/integrations/pom.xml deleted file mode 100644 index 0c190aeff27..00000000000 --- a/examples/integrations/pom.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples - helidon-examples-project - 4.1.0-SNAPSHOT - - io.helidon.examples.integrations - helidon-examples-integrations-project - Helidon Examples Integrations - pom - - - cdi - micronaut - neo4j - micrometer - oci - vault - microstream - - - diff --git a/examples/integrations/vault/hcp-cdi/README.md b/examples/integrations/vault/hcp-cdi/README.md deleted file mode 100644 index 764dabb49a4..00000000000 --- a/examples/integrations/vault/hcp-cdi/README.md +++ /dev/null @@ -1,26 +0,0 @@ -HCP Vault Integration with Helidon APIs ---- - -This example expects an empty Vault. It uses the token to create all required resources. - -To run this example: - -1. Run a docker image with a known root token - -```shell -docker run --cap-add=IPC_LOCK -e VAULT_DEV_ROOT_TOKEN_ID=myroot -d --name=vault -p8200:8200 vault -``` - -2. Build this application - -```shell -mvn clean package -``` - -3. Start this application - -```shell -java -jar ./target/helidon-examples-integrations-vault-hcp-cdi.jar -``` - -4. Exercise the endpoints \ No newline at end of file diff --git a/examples/integrations/vault/hcp-cdi/pom.xml b/examples/integrations/vault/hcp-cdi/pom.xml deleted file mode 100644 index 3c73bd5344d..00000000000 --- a/examples/integrations/vault/hcp-cdi/pom.xml +++ /dev/null @@ -1,100 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../../applications/mp/pom.xml - - - io.helidon.examples.integrations.vault - helidon-examples-integrations-vault-hcp-cdi - Helidon Examples Integration Vault CDI - CDI integration with Vault. - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.integrations.vault - helidon-integrations-vault-cdi - - - io.helidon.config - helidon-config-yaml - - - io.helidon.integrations.vault.auths - helidon-integrations-vault-auths-token - - - io.helidon.integrations.vault.auths - helidon-integrations-vault-auths-approle - - - io.helidon.integrations.vault.secrets - helidon-integrations-vault-secrets-kv1 - - - io.helidon.integrations.vault.secrets - helidon-integrations-vault-secrets-kv2 - - - io.helidon.integrations.vault.secrets - helidon-integrations-vault-secrets-cubbyhole - - - io.helidon.integrations.vault.secrets - helidon-integrations-vault-secrets-transit - - - io.helidon.integrations.vault.sys - helidon-integrations-vault-sys - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/CubbyholeResource.java b/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/CubbyholeResource.java deleted file mode 100644 index e0c9a7671f9..00000000000 --- a/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/CubbyholeResource.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.vault.hcp.cdi; - -import java.util.Map; -import java.util.Optional; - -import io.helidon.integrations.vault.Secret; -import io.helidon.integrations.vault.secrets.cubbyhole.CreateCubbyhole; -import io.helidon.integrations.vault.secrets.cubbyhole.CubbyholeSecrets; -import io.helidon.integrations.vault.secrets.cubbyhole.DeleteCubbyhole; - -import jakarta.inject.Inject; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.core.Response; - -/** - * JAX-RS resource for Cubbyhole secrets engine operations. - */ -@Path("/cubbyhole") -public class CubbyholeResource { - private final CubbyholeSecrets secrets; - - @Inject - CubbyholeResource(CubbyholeSecrets secrets) { - this.secrets = secrets; - } - - /** - * Create a secret from request entity, the name of the value is {@code secret}. - * - * @param path path of the secret taken from request path - * @param secret secret from the entity - * @return response - */ - @POST - @Path("/secrets/{path: .*}") - public Response createSecret(@PathParam("path") String path, String secret) { - CreateCubbyhole.Response response = secrets.create(path, Map.of("secret", secret)); - - return Response.ok() - .entity("Created secret on path: " + path + ", key is \"secret\", original status: " + response.status().code()) - .build(); - } - - /** - * Delete the secret on a specified path. - * - * @param path path of the secret taken from request path - * @return response - */ - @DELETE - @Path("/secrets/{path: .*}") - public Response deleteSecret(@PathParam("path") String path) { - DeleteCubbyhole.Response response = secrets.delete(path); - - return Response.ok() - .entity("Deleted secret on path: " + path + ". Original status: " + response.status().code()) - .build(); - } - - /** - * Get the secret on a specified path. - * - * @param path path of the secret taken from request path - * @return response - */ - @GET - @Path("/secrets/{path: .*}") - public Response getSecret(@PathParam("path") String path) { - Optional secret = secrets.get(path); - - if (secret.isPresent()) { - return Response.ok() - .entity("Secret: " + secret.get().values().toString()) - .build(); - } else { - return Response.status(Response.Status.NOT_FOUND).build(); - } - } -} diff --git a/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/Kv1Resource.java b/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/Kv1Resource.java deleted file mode 100644 index 222f166e430..00000000000 --- a/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/Kv1Resource.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.vault.hcp.cdi; - -import java.util.Map; -import java.util.Optional; - -import io.helidon.integrations.vault.Secret; -import io.helidon.integrations.vault.secrets.kv1.CreateKv1; -import io.helidon.integrations.vault.secrets.kv1.DeleteKv1; -import io.helidon.integrations.vault.secrets.kv1.Kv1Secrets; -import io.helidon.integrations.vault.sys.DisableEngine; -import io.helidon.integrations.vault.sys.EnableEngine; -import io.helidon.integrations.vault.sys.Sys; - -import jakarta.inject.Inject; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.core.Response; - -/** - * JAX-RS resource for Key/Value version 1 secrets engine operations. - */ -@Path("/kv1") -public class Kv1Resource { - private final Sys sys; - private final Kv1Secrets secrets; - - @Inject - Kv1Resource(Sys sys, Kv1Secrets secrets) { - this.sys = sys; - this.secrets = secrets; - } - - /** - * Enable the secrets engine on the default path. - * - * @return response - */ - @Path("/engine") - @GET - public Response enableEngine() { - EnableEngine.Response response = sys.enableEngine(Kv1Secrets.ENGINE); - - return Response.ok() - .entity("Key/value version 1 secret engine is now enabled. Original status: " + response.status().code()) - .build(); - } - - /** - * Disable the secrets engine on the default path. - * @return response - */ - @Path("/engine") - @DELETE - public Response disableEngine() { - DisableEngine.Response response = sys.disableEngine(Kv1Secrets.ENGINE); - return Response.ok() - .entity("Key/value version 1 secret engine is now disabled. Original status: " + response.status().code()) - .build(); - } - - /** - * Create a secret from request entity, the name of the value is {@code secret}. - * - * @param path path of the secret taken from request path - * @param secret secret from the entity - * @return response - */ - @POST - @Path("/secrets/{path: .*}") - public Response createSecret(@PathParam("path") String path, String secret) { - CreateKv1.Response response = secrets.create(path, Map.of("secret", secret)); - - return Response.ok() - .entity("Created secret on path: " + path + ", key is \"secret\", original status: " + response.status().code()) - .build(); - } - - /** - * Delete the secret on a specified path. - * - * @param path path of the secret taken from request path - * @return response - */ - @DELETE - @Path("/secrets/{path: .*}") - public Response deleteSecret(@PathParam("path") String path) { - DeleteKv1.Response response = secrets.delete(path); - - return Response.ok() - .entity("Deleted secret on path: " + path + ". Original status: " + response.status().code()) - .build(); - } - - /** - * Get the secret on a specified path. - * - * @param path path of the secret taken from request path - * @return response - */ - @GET - @Path("/secrets/{path: .*}") - public Response getSecret(@PathParam("path") String path) { - Optional secret = secrets.get(path); - - if (secret.isPresent()) { - Secret kv1Secret = secret.get(); - return Response.ok() - .entity("Secret: " + secret.get().values().toString()) - .build(); - } else { - return Response.status(Response.Status.NOT_FOUND).build(); - } - } -} diff --git a/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/Kv2Resource.java b/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/Kv2Resource.java deleted file mode 100644 index 05ef0b81cd5..00000000000 --- a/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/Kv2Resource.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2021 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.integrations.vault.hcp.cdi; - -import java.util.Map; -import java.util.Optional; - -import io.helidon.integrations.vault.secrets.kv2.CreateKv2; -import io.helidon.integrations.vault.secrets.kv2.DeleteAllKv2; -import io.helidon.integrations.vault.secrets.kv2.Kv2Secret; -import io.helidon.integrations.vault.secrets.kv2.Kv2Secrets; - -import jakarta.inject.Inject; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.core.Response; - -/** - * JAX-RS resource for Key/Value version 2 secrets engine operations. - */ -@Path("/kv2") -public class Kv2Resource { - private final Kv2Secrets secrets; - - @Inject - Kv2Resource(Kv2Secrets secrets) { - this.secrets = secrets; - } - - /** - * Create a secret from request entity, the name of the value is {@code secret}. - * - * @param path path of the secret taken from request path - * @param secret secret from the entity - * @return response - */ - @POST - @Path("/secrets/{path: .*}") - public Response createSecret(@PathParam("path") String path, String secret) { - CreateKv2.Response response = secrets.create(path, Map.of("secret", secret)); - - return Response.ok() - .entity("Created secret on path: " + path + ", key is \"secret\", original status: " + response.status().code()) - .build(); - } - - /** - * Delete the secret on a specified path. - * - * @param path path of the secret taken from request path - * @return response - */ - @DELETE - @Path("/secrets/{path: .*}") - public Response deleteSecret(@PathParam("path") String path) { - DeleteAllKv2.Response response = secrets.deleteAll(path); - - return Response.ok() - .entity("Deleted secret on path: " + path + ". Original status: " + response.status().code()) - .build(); - } - - /** - * Get the secret on a specified path. - * - * @param path path of the secret taken from request path - * @return response - */ - @GET - @Path("/secrets/{path: .*}") - public Response getSecret(@PathParam("path") String path) { - - Optional secret = secrets.get(path); - - if (secret.isPresent()) { - Kv2Secret kv2Secret = secret.get(); - return Response.ok() - .entity("Version " + kv2Secret.metadata().version() + ", secret: " + kv2Secret.values().toString()) - .build(); - } else { - return Response.status(Response.Status.NOT_FOUND).build(); - } - } -} diff --git a/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/TransitResource.java b/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/TransitResource.java deleted file mode 100644 index 15d80a5f05d..00000000000 --- a/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/TransitResource.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.vault.hcp.cdi; - -import io.helidon.common.Base64Value; -import io.helidon.integrations.vault.secrets.transit.CreateKey; -import io.helidon.integrations.vault.secrets.transit.Decrypt; -import io.helidon.integrations.vault.secrets.transit.DeleteKey; -import io.helidon.integrations.vault.secrets.transit.Encrypt; -import io.helidon.integrations.vault.secrets.transit.Hmac; -import io.helidon.integrations.vault.secrets.transit.Sign; -import io.helidon.integrations.vault.secrets.transit.TransitSecrets; -import io.helidon.integrations.vault.secrets.transit.UpdateKeyConfig; -import io.helidon.integrations.vault.secrets.transit.Verify; -import io.helidon.integrations.vault.sys.DisableEngine; -import io.helidon.integrations.vault.sys.EnableEngine; -import io.helidon.integrations.vault.sys.Sys; - -import jakarta.inject.Inject; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.core.Response; - -/** - * JAX-RS resource for Transit secrets engine operations. - */ -@Path("/transit") -public class TransitResource { - private static final String ENCRYPTION_KEY = "encryption-key"; - private static final String SIGNATURE_KEY = "signature-key"; - - private final Sys sys; - private final TransitSecrets secrets; - - @Inject - TransitResource(Sys sys, TransitSecrets secrets) { - this.sys = sys; - this.secrets = secrets; - } - - /** - * Enable the secrets engine on the default path. - * - * @return response - */ - @Path("/engine") - @GET - public Response enableEngine() { - EnableEngine.Response response = sys.enableEngine(TransitSecrets.ENGINE); - - return Response.ok() - .entity("Transit secret engine is now enabled. Original status: " + response.status().code()) - .build(); - } - - /** - * Disable the secrets engine on the default path. - * @return response - */ - @Path("/engine") - @DELETE - public Response disableEngine() { - DisableEngine.Response response = sys.disableEngine(TransitSecrets.ENGINE); - - return Response.ok() - .entity("Transit secret engine is now disabled. Original status: " + response.status()) - .build(); - } - - /** - * Create the encrypting and signature keys. - * - * @return response - */ - @Path("/keys") - @GET - public Response createKeys() { - secrets.createKey(CreateKey.Request.builder() - .name(ENCRYPTION_KEY)); - - secrets.createKey(CreateKey.Request.builder() - .name(SIGNATURE_KEY) - .type("rsa-2048")); - - return Response.ok() - .entity("Created encryption (and HMAC), and signature keys") - .build(); - } - - /** - * Delete the encryption and signature keys. - * - * @return response - */ - @Path("/keys") - @DELETE - public Response deleteKeys() { - // we must first enable deletion of the key (by default it cannot be deleted) - secrets.updateKeyConfig(UpdateKeyConfig.Request.builder() - .name(ENCRYPTION_KEY) - .allowDeletion(true)); - - secrets.updateKeyConfig(UpdateKeyConfig.Request.builder() - .name(SIGNATURE_KEY) - .allowDeletion(true)); - - secrets.deleteKey(DeleteKey.Request.create(ENCRYPTION_KEY)); - secrets.deleteKey(DeleteKey.Request.create(SIGNATURE_KEY)); - - return Response.ok() - .entity("Deleted encryption (and HMAC), and signature keys") - .build(); - } - - /** - * Encrypt a secret. - * - * @param secret provided as part of the path - * @return cipher text - */ - @Path("/encrypt/{secret: .*}") - @GET - public String encryptSecret(@PathParam("secret") String secret) { - return secrets.encrypt(Encrypt.Request.builder() - .encryptionKeyName(ENCRYPTION_KEY) - .data(Base64Value.create(secret))) - .encrypted() - .cipherText(); - } - - /** - * Decrypt a secret. - * - * @param cipherText provided as part of the path - * @return decrypted secret text - */ - @Path("/decrypt/{cipherText: .*}") - @GET - public String decryptSecret(@PathParam("cipherText") String cipherText) { - return secrets.decrypt(Decrypt.Request.builder() - .encryptionKeyName(ENCRYPTION_KEY) - .cipherText(cipherText)) - .decrypted() - .toDecodedString(); - } - - /** - * Create an HMAC for text. - * - * @param text text to do HMAC for - * @return hmac string that can be used to {@link #verifyHmac(String, String)} - */ - @Path("/hmac/{text}") - @GET - public String hmac(@PathParam("text") String text) { - return secrets.hmac(Hmac.Request.builder() - .hmacKeyName(ENCRYPTION_KEY) - .data(Base64Value.create(text))) - .hmac(); - } - - /** - * Create a signature for text. - * - * @param text text to sign - * @return signature string that can be used to {@link #verifySignature(String, String)} - */ - @Path("/sign/{text}") - @GET - public String sign(@PathParam("text") String text) { - return secrets.sign(Sign.Request.builder() - .signatureKeyName(SIGNATURE_KEY) - .data(Base64Value.create(text))) - .signature(); - } - - /** - * Verify HMAC. - * - * @param secret secret that was used to {@link #hmac(String)} - * @param hmac HMAC text - * @return {@code HMAC Valid} or {@code HMAC Invalid} - */ - @Path("/verify/hmac/{secret}/{hmac: .*}") - @GET - public String verifyHmac(@PathParam("secret") String secret, @PathParam("hmac") String hmac) { - boolean isValid = secrets.verify(Verify.Request.builder() - .digestKeyName(ENCRYPTION_KEY) - .data(Base64Value.create(secret)) - .hmac(hmac)) - .isValid(); - - return (isValid ? "HMAC Valid" : "HMAC Invalid"); - } - - /** - * Verify signature. - * - * @param secret secret that was used to {@link #sign(String)} - * @param signature signature - * @return {@code Signature Valid} or {@code Signature Invalid} - */ - @Path("/verify/sign/{secret}/{signature: .*}") - @GET - public String verifySignature(@PathParam("secret") String secret, @PathParam("signature") String signature) { - boolean isValid = secrets.verify(Verify.Request.builder() - .digestKeyName(SIGNATURE_KEY) - .data(Base64Value.create(secret)) - .signature(signature)) - .isValid(); - - return (isValid ? "Signature Valid" : "Signature Invalid"); - } -} diff --git a/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/VaultCdiMain.java b/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/VaultCdiMain.java deleted file mode 100644 index 82fd04ca2f0..00000000000 --- a/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/VaultCdiMain.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2021 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.integrations.vault.hcp.cdi; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; - -import io.helidon.config.yaml.mp.YamlMpConfigSource; -import io.helidon.microprofile.cdi.Main; - -import org.eclipse.microprofile.config.Config; -import org.eclipse.microprofile.config.spi.ConfigProviderResolver; -import org.eclipse.microprofile.config.spi.ConfigSource; - -/** - * Main class of example. - */ -public final class VaultCdiMain { - private VaultCdiMain() { - } - - /** - * Main method of example. - * - * @param args ignored - */ - public static void main(String[] args) { - ConfigProviderResolver configProvider = ConfigProviderResolver.instance(); - - Config mpConfig = configProvider.getBuilder() - .addDefaultSources() - .withSources(examplesConfig()) - .addDiscoveredSources() - .addDiscoveredConverters() - .build(); - - // configure - configProvider.registerConfig(mpConfig, null); - - // start CDI - Main.main(args); - } - - private static ConfigSource[] examplesConfig() { - Path path = Paths.get(System.getProperty("user.home") + "/helidon/conf/examples.yaml"); - if (Files.exists(path)) { - return new ConfigSource[] {YamlMpConfigSource.create(path)}; - } - return new ConfigSource[0]; - } -} diff --git a/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/package-info.java b/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/package-info.java deleted file mode 100644 index 05acc2464ff..00000000000 --- a/examples/integrations/vault/hcp-cdi/src/main/java/io/helidon/examples/integrations/vault/hcp/cdi/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 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 of Helidon integration with Hashicorp Vault within CDI. - */ -package io.helidon.examples.integrations.vault.hcp.cdi; diff --git a/examples/integrations/vault/hcp-cdi/src/main/resources/META-INF/beans.xml b/examples/integrations/vault/hcp-cdi/src/main/resources/META-INF/beans.xml deleted file mode 100644 index dbf3e648c1e..00000000000 --- a/examples/integrations/vault/hcp-cdi/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/integrations/vault/hcp-cdi/src/main/resources/application.yaml b/examples/integrations/vault/hcp-cdi/src/main/resources/application.yaml deleted file mode 100644 index d028f2cbca7..00000000000 --- a/examples/integrations/vault/hcp-cdi/src/main/resources/application.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright (c) 2021 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 - -vault: - default: - address: "http://localhost:8200" - token: "myroot" - auth: - app-role: - enabled: false - token: - enabled: true diff --git a/examples/integrations/vault/hcp-cdi/src/main/resources/logging.properties b/examples/integrations/vault/hcp-cdi/src/main/resources/logging.properties deleted file mode 100644 index f8802f90626..00000000000 --- a/examples/integrations/vault/hcp-cdi/src/main/resources/logging.properties +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright (c) 2021, 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. -# - -# Send messages to the console -handlers=io.helidon.logging.jul.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 - -io.helidon.level=INFO -io.helidon.integrations.level=INFO diff --git a/examples/integrations/vault/hcp/README.md b/examples/integrations/vault/hcp/README.md deleted file mode 100644 index 1bcbac31d2d..00000000000 --- a/examples/integrations/vault/hcp/README.md +++ /dev/null @@ -1,26 +0,0 @@ -HCP Vault Integration ---- - -This example expects an empty Vault. It uses the token to create all required resources. - -To run this example: - -1. Run a docker image with a known root token - -```shell -docker run --cap-add=IPC_LOCK -e VAULT_DEV_ROOT_TOKEN_ID=myroot -d --name=vault -p8200:8200 vault -``` - -2. Build this application - -```shell -mvn clean package -``` - -3. Start this application - -```shell -java -jar ./target/helidon-examples-integrations-vault-hcp.jar -``` - -4. Exercise the endpoints \ No newline at end of file diff --git a/examples/integrations/vault/hcp/pom.xml b/examples/integrations/vault/hcp/pom.xml deleted file mode 100644 index f810dcf76a4..00000000000 --- a/examples/integrations/vault/hcp/pom.xml +++ /dev/null @@ -1,99 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../../applications/se/pom.xml - - - io.helidon.examples.integrations.vault - helidon-examples-integrations-vault-hcp - Helidon Examples Integration Vault - Helidon integration with Vault. - - - io.helidon.examples.integrations.vault.hcp.VaultMain - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.integrations.vault - helidon-integrations-vault - - - io.helidon.config - helidon-config-yaml - - - io.helidon.integrations.vault.auths - helidon-integrations-vault-auths-token - - - io.helidon.integrations.vault.auths - helidon-integrations-vault-auths-approle - - - io.helidon.integrations.vault.auths - helidon-integrations-vault-auths-k8s - - - io.helidon.integrations.vault.secrets - helidon-integrations-vault-secrets-kv1 - - - io.helidon.integrations.vault.secrets - helidon-integrations-vault-secrets-kv2 - - - io.helidon.integrations.vault.secrets - helidon-integrations-vault-secrets-cubbyhole - - - io.helidon.integrations.vault.secrets - helidon-integrations-vault-secrets-transit - - - io.helidon.integrations.vault.sys - helidon-integrations-vault-sys - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/integrations/vault/hcp/src/main/java/io/helidon/examples/integrations/vault/hcp/AppRoleExample.java b/examples/integrations/vault/hcp/src/main/java/io/helidon/examples/integrations/vault/hcp/AppRoleExample.java deleted file mode 100644 index e75a8a67802..00000000000 --- a/examples/integrations/vault/hcp/src/main/java/io/helidon/examples/integrations/vault/hcp/AppRoleExample.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.vault.hcp; - -import java.time.Duration; -import java.util.Map; -import java.util.Optional; - -import io.helidon.config.Config; -import io.helidon.integrations.vault.Vault; -import io.helidon.integrations.vault.auths.approle.AppRoleAuth; -import io.helidon.integrations.vault.auths.approle.AppRoleVaultAuth; -import io.helidon.integrations.vault.auths.approle.CreateAppRole; -import io.helidon.integrations.vault.auths.approle.GenerateSecretId; -import io.helidon.integrations.vault.secrets.kv2.Kv2Secret; -import io.helidon.integrations.vault.secrets.kv2.Kv2Secrets; -import io.helidon.integrations.vault.sys.EnableAuth; -import io.helidon.integrations.vault.sys.Sys; - -class AppRoleExample { - private static final String SECRET_PATH = "approle/example/secret"; - private static final String ROLE_NAME = "approle_role"; - private static final String POLICY_NAME = "approle_policy"; - private static final String CUSTOM_APP_ROLE_PATH = "customapprole"; - - private final Vault tokenVault; - private final Config config; - private final Sys sys; - - private Vault appRoleVault; - - AppRoleExample(Vault tokenVault, Config config) { - this.tokenVault = tokenVault; - this.config = config; - - this.sys = tokenVault.sys(Sys.API); - } - - public String run() { - /* - The following tasks must be run before we authenticate - */ - enableAppRoleAuth(); - workWithSecrets(); - disableAppRoleAuth(); - return "AppRole example finished successfully."; - } - - private void workWithSecrets() { - Kv2Secrets secrets = appRoleVault.secrets(Kv2Secrets.ENGINE); - secrets.create(SECRET_PATH, Map.of("secret-key", "secretValue", - "secret-user", "username")); - Optional secret = secrets.get(SECRET_PATH); - if (secret.isPresent()) { - Kv2Secret kv2Secret = secret.get(); - System.out.println("appRole first secret: " + kv2Secret.value("secret-key")); - System.out.println("appRole second secret: " + kv2Secret.value("secret-user")); - } else { - System.out.println("appRole secret not found"); - } - secrets.deleteAll(SECRET_PATH); - } - - private void disableAppRoleAuth() { - sys.deletePolicy(POLICY_NAME); - sys.disableAuth(CUSTOM_APP_ROLE_PATH); - } - - private void enableAppRoleAuth() { - - // enable the method - sys.enableAuth(EnableAuth.Request.builder() - .auth(AppRoleAuth.AUTH_METHOD) - // must be aligned with path configured in application.yaml - .path(CUSTOM_APP_ROLE_PATH)); - - // add policy - sys.createPolicy(POLICY_NAME, VaultPolicy.POLICY); - - tokenVault.auth(AppRoleAuth.AUTH_METHOD, CUSTOM_APP_ROLE_PATH) - .createAppRole(CreateAppRole.Request.builder() - .roleName(ROLE_NAME) - .addTokenPolicy(POLICY_NAME) - .tokenExplicitMaxTtl(Duration.ofMinutes(1))); - - String roleId = tokenVault.auth(AppRoleAuth.AUTH_METHOD, CUSTOM_APP_ROLE_PATH) - .readRoleId(ROLE_NAME) - .orElseThrow(); - - - GenerateSecretId.Response response = tokenVault.auth(AppRoleAuth.AUTH_METHOD, CUSTOM_APP_ROLE_PATH) - .generateSecretId(GenerateSecretId.Request.builder() - .roleName(ROLE_NAME) - .addMetadata("name", "helidon")); - - String secretId = response.secretId(); - - System.out.println("roleId: " + roleId); - System.out.println("secretId: " + secretId); - appRoleVault = Vault.builder() - .config(config) - .addVaultAuth(AppRoleVaultAuth.builder() - .path(CUSTOM_APP_ROLE_PATH) - .appRoleId(roleId) - .secretId(secretId) - .build()) - .build(); - } -} diff --git a/examples/integrations/vault/hcp/src/main/java/io/helidon/examples/integrations/vault/hcp/CubbyholeService.java b/examples/integrations/vault/hcp/src/main/java/io/helidon/examples/integrations/vault/hcp/CubbyholeService.java deleted file mode 100644 index 2fa24d2c8d3..00000000000 --- a/examples/integrations/vault/hcp/src/main/java/io/helidon/examples/integrations/vault/hcp/CubbyholeService.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.vault.hcp; - -import java.util.Map; -import java.util.Optional; - -import io.helidon.http.Status; -import io.helidon.integrations.vault.Secret; -import io.helidon.integrations.vault.secrets.cubbyhole.CubbyholeSecrets; -import io.helidon.integrations.vault.sys.Sys; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -class CubbyholeService implements HttpService { - private final Sys sys; - private final CubbyholeSecrets secrets; - - CubbyholeService(Sys sys, CubbyholeSecrets secrets) { - this.sys = sys; - this.secrets = secrets; - } - - @Override - public void routing(HttpRules rules) { - rules.get("/create", this::createSecrets) - .get("/secrets/{path:.*}", this::getSecret); - } - - private void createSecrets(ServerRequest req, ServerResponse res) { - secrets.create("first/secret", Map.of("key", "secretValue")); - res.send("Created secret on path /first/secret"); - } - - private void getSecret(ServerRequest req, ServerResponse res) { - String path = req.path().pathParameters().get("path"); - Optional secret = secrets.get(path); - if (secret.isPresent()) { - // using toString so we do not need to depend on JSON-B - res.send(secret.get().values().toString()); - } else { - res.status(Status.NOT_FOUND_404); - res.send(); - } - } -} diff --git a/examples/integrations/vault/hcp/src/main/java/io/helidon/examples/integrations/vault/hcp/K8sExample.java b/examples/integrations/vault/hcp/src/main/java/io/helidon/examples/integrations/vault/hcp/K8sExample.java deleted file mode 100644 index b389be50de5..00000000000 --- a/examples/integrations/vault/hcp/src/main/java/io/helidon/examples/integrations/vault/hcp/K8sExample.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.vault.hcp; - -import java.util.Map; -import java.util.Optional; - -import io.helidon.config.Config; -import io.helidon.integrations.vault.Vault; -import io.helidon.integrations.vault.auths.k8s.ConfigureK8s; -import io.helidon.integrations.vault.auths.k8s.CreateRole; -import io.helidon.integrations.vault.auths.k8s.K8sAuth; -import io.helidon.integrations.vault.secrets.kv2.Kv2Secret; -import io.helidon.integrations.vault.secrets.kv2.Kv2Secrets; -import io.helidon.integrations.vault.sys.Sys; - -class K8sExample { - private static final String SECRET_PATH = "k8s/example/secret"; - private static final String POLICY_NAME = "k8s_policy"; - - private final Vault tokenVault; - private final String k8sAddress; - private final Config config; - private final Sys sys; - - private Vault k8sVault; - - K8sExample(Vault tokenVault, Config config) { - this.tokenVault = tokenVault; - this.sys = tokenVault.sys(Sys.API); - this.k8sAddress = config.get("cluster-address").asString().get(); - this.config = config; - } - - public String run() { - /* - The following tasks must be run before we authenticate - */ - enableK8sAuth(); - // Now we can login using k8s - must run within a k8s cluster (or you need the k8s configuration files locally) - workWithSecrets(); - // Now back to token based Vault, as we will clean up - disableK8sAuth(); - return "k8s example finished successfully."; - } - - private void workWithSecrets() { - Kv2Secrets secrets = k8sVault.secrets(Kv2Secrets.ENGINE); - - secrets.create(SECRET_PATH, Map.of("secret-key", "secretValue", - "secret-user", "username")); - - Optional secret = secrets.get(SECRET_PATH); - if (secret.isPresent()) { - Kv2Secret kv2Secret = secret.get(); - System.out.println("k8s first secret: " + kv2Secret.value("secret-key")); - System.out.println("k8s second secret: " + kv2Secret.value("secret-user")); - } else { - System.out.println("k8s secret not found"); - } - secrets.deleteAll(SECRET_PATH); - } - - private void disableK8sAuth() { - sys.deletePolicy(POLICY_NAME); - sys.disableAuth(K8sAuth.AUTH_METHOD.defaultPath()); - } - - private void enableK8sAuth() { - // enable the method - sys.enableAuth(K8sAuth.AUTH_METHOD); - sys.createPolicy(POLICY_NAME, VaultPolicy.POLICY); - tokenVault.auth(K8sAuth.AUTH_METHOD) - .configure(ConfigureK8s.Request.builder() - .address(k8sAddress)); - tokenVault.auth(K8sAuth.AUTH_METHOD) - // this must be the same role name as is defined in application.yaml - .createRole(CreateRole.Request.builder() - .roleName("my-role") - .addBoundServiceAccountName("*") - .addBoundServiceAccountNamespace("default") - .addTokenPolicy(POLICY_NAME)); - k8sVault = Vault.create(config); - } -} diff --git a/examples/integrations/vault/hcp/src/main/java/io/helidon/examples/integrations/vault/hcp/Kv1Service.java b/examples/integrations/vault/hcp/src/main/java/io/helidon/examples/integrations/vault/hcp/Kv1Service.java deleted file mode 100644 index 4f8edae62dc..00000000000 --- a/examples/integrations/vault/hcp/src/main/java/io/helidon/examples/integrations/vault/hcp/Kv1Service.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.vault.hcp; - -import java.util.Map; -import java.util.Optional; - -import io.helidon.http.Status; -import io.helidon.integrations.vault.Secret; -import io.helidon.integrations.vault.secrets.kv1.Kv1Secrets; -import io.helidon.integrations.vault.sys.Sys; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -class Kv1Service implements HttpService { - private final Sys sys; - private final Kv1Secrets secrets; - - Kv1Service(Sys sys, Kv1Secrets secrets) { - this.sys = sys; - this.secrets = secrets; - } - - @Override - public void routing(HttpRules rules) { - rules.get("/enable", this::enableEngine) - .get("/create", this::createSecrets) - .get("/secrets/{path:.*}", this::getSecret) - .delete("/secrets/{path:.*}", this::deleteSecret) - .get("/disable", this::disableEngine); - } - - private void disableEngine(ServerRequest req, ServerResponse res) { - sys.disableEngine(Kv1Secrets.ENGINE); - res.send("KV1 Secret engine disabled"); - } - - private void enableEngine(ServerRequest req, ServerResponse res) { - sys.enableEngine(Kv1Secrets.ENGINE); - res.send("KV1 Secret engine enabled"); - } - - private void createSecrets(ServerRequest req, ServerResponse res) { - secrets.create("first/secret", Map.of("key", "secretValue")); - res.send("Created secret on path /first/secret"); - } - - private void deleteSecret(ServerRequest req, ServerResponse res) { - String path = req.path().pathParameters().get("path"); - secrets.delete(path); - res.send("Deleted secret on path " + path); - } - - private void getSecret(ServerRequest req, ServerResponse res) { - String path = req.path().pathParameters().get("path"); - - Optional secret = secrets.get(path); - if (secret.isPresent()) { - // using toString so we do not need to depend on JSON-B - res.send(secret.get().values().toString()); - } else { - res.status(Status.NOT_FOUND_404); - res.send(); - } - } -} diff --git a/examples/integrations/vault/hcp/src/main/java/io/helidon/examples/integrations/vault/hcp/Kv2Service.java b/examples/integrations/vault/hcp/src/main/java/io/helidon/examples/integrations/vault/hcp/Kv2Service.java deleted file mode 100644 index a93395a1715..00000000000 --- a/examples/integrations/vault/hcp/src/main/java/io/helidon/examples/integrations/vault/hcp/Kv2Service.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.vault.hcp; - -import java.util.Map; -import java.util.Optional; - -import io.helidon.http.Status; -import io.helidon.integrations.vault.secrets.kv2.Kv2Secret; -import io.helidon.integrations.vault.secrets.kv2.Kv2Secrets; -import io.helidon.integrations.vault.sys.Sys; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -class Kv2Service implements HttpService { - private final Sys sys; - private final Kv2Secrets secrets; - - Kv2Service(Sys sys, Kv2Secrets secrets) { - this.sys = sys; - this.secrets = secrets; - } - - @Override - public void routing(HttpRules rules) { - rules.get("/create", this::createSecrets) - .get("/secrets/{path:.*}", this::getSecret) - .delete("/secrets/{path:.*}", this::deleteSecret); - } - - private void createSecrets(ServerRequest req, ServerResponse res) { - secrets.create("first/secret", Map.of("key", "secretValue")); - res.send("Created secret on path /first/secret"); - } - - private void deleteSecret(ServerRequest req, ServerResponse res) { - String path = req.path().pathParameters().get("path"); - secrets.deleteAll(path); - res.send("Deleted secret on path " + path); - } - - private void getSecret(ServerRequest req, ServerResponse res) { - String path = req.path().pathParameters().get("path"); - - Optional secret = secrets.get(path); - if (secret.isPresent()) { - // using toString so we do not need to depend on JSON-B - Kv2Secret kv2Secret = secret.get(); - res.send("Version " + kv2Secret.metadata().version() + ", secret: " + kv2Secret.values().toString()); - } else { - res.status(Status.NOT_FOUND_404); - res.send(); - } - } -} diff --git a/examples/integrations/vault/hcp/src/main/java/io/helidon/examples/integrations/vault/hcp/TransitService.java b/examples/integrations/vault/hcp/src/main/java/io/helidon/examples/integrations/vault/hcp/TransitService.java deleted file mode 100644 index b520ca2e3f0..00000000000 --- a/examples/integrations/vault/hcp/src/main/java/io/helidon/examples/integrations/vault/hcp/TransitService.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.vault.hcp; - -import java.util.List; - -import io.helidon.common.Base64Value; -import io.helidon.integrations.vault.secrets.transit.CreateKey; -import io.helidon.integrations.vault.secrets.transit.Decrypt; -import io.helidon.integrations.vault.secrets.transit.DecryptBatch; -import io.helidon.integrations.vault.secrets.transit.DeleteKey; -import io.helidon.integrations.vault.secrets.transit.Encrypt; -import io.helidon.integrations.vault.secrets.transit.EncryptBatch; -import io.helidon.integrations.vault.secrets.transit.Hmac; -import io.helidon.integrations.vault.secrets.transit.Sign; -import io.helidon.integrations.vault.secrets.transit.TransitSecrets; -import io.helidon.integrations.vault.secrets.transit.UpdateKeyConfig; -import io.helidon.integrations.vault.secrets.transit.Verify; -import io.helidon.integrations.vault.sys.Sys; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -class TransitService implements HttpService { - private static final String ENCRYPTION_KEY = "encryption-key"; - private static final String SIGNATURE_KEY = "signature-key"; - private static final Base64Value SECRET_STRING = Base64Value.create("Hello World"); - private final Sys sys; - private final TransitSecrets secrets; - - TransitService(Sys sys, TransitSecrets secrets) { - this.sys = sys; - this.secrets = secrets; - } - - @Override - public void routing(HttpRules rules) { - rules.get("/enable", this::enableEngine) - .get("/keys", this::createKeys) - .delete("/keys", this::deleteKeys) - .get("/batch", this::batch) - .get("/encrypt/{text:.*}", this::encryptSecret) - .get("/decrypt/{text:.*}", this::decryptSecret) - .get("/sign", this::sign) - .get("/hmac", this::hmac) - .get("/verify/sign/{text:.*}", this::verify) - .get("/verify/hmac/{text:.*}", this::verifyHmac) - .get("/disable", this::disableEngine); - } - - private void enableEngine(ServerRequest req, ServerResponse res) { - sys.enableEngine(TransitSecrets.ENGINE); - res.send("Transit Secret engine enabled"); - } - - private void disableEngine(ServerRequest req, ServerResponse res) { - sys.disableEngine(TransitSecrets.ENGINE); - res.send("Transit Secret engine disabled"); - } - - private void createKeys(ServerRequest req, ServerResponse res) { - CreateKey.Request request = CreateKey.Request.builder() - .name(ENCRYPTION_KEY); - - secrets.createKey(request); - secrets.createKey(CreateKey.Request.builder() - .name(SIGNATURE_KEY) - .type("rsa-2048")); - - res.send("Created keys"); - } - - private void deleteKeys(ServerRequest req, ServerResponse res) { - secrets.updateKeyConfig(UpdateKeyConfig.Request.builder() - .name(ENCRYPTION_KEY) - .allowDeletion(true)); - System.out.println("Updated key config"); - - secrets.deleteKey(DeleteKey.Request.create(ENCRYPTION_KEY)); - - res.send("Deleted key."); - } - - private void decryptSecret(ServerRequest req, ServerResponse res) { - String encrypted = req.path().pathParameters().get("text"); - - Decrypt.Response decryptResponse = secrets.decrypt(Decrypt.Request.builder() - .encryptionKeyName(ENCRYPTION_KEY) - .cipherText(encrypted)); - - res.send(String.valueOf(decryptResponse.decrypted().toDecodedString())); - } - - private void encryptSecret(ServerRequest req, ServerResponse res) { - String secret = req.path().pathParameters().get("text"); - - Encrypt.Response encryptResponse = secrets.encrypt(Encrypt.Request.builder() - .encryptionKeyName(ENCRYPTION_KEY) - .data(Base64Value.create(secret))); - - res.send(encryptResponse.encrypted().cipherText()); - } - - private void hmac(ServerRequest req, ServerResponse res) { - Hmac.Response hmacResponse = secrets.hmac(Hmac.Request.builder() - .hmacKeyName(ENCRYPTION_KEY) - .data(SECRET_STRING)); - - res.send(hmacResponse.hmac()); - } - - private void sign(ServerRequest req, ServerResponse res) { - Sign.Response signResponse = secrets.sign(Sign.Request.builder() - .signatureKeyName(SIGNATURE_KEY) - .data(SECRET_STRING)); - - res.send(signResponse.signature()); - } - - private void verifyHmac(ServerRequest req, ServerResponse res) { - String hmac = req.path().pathParameters().get("text"); - - Verify.Response verifyResponse = secrets.verify(Verify.Request.builder() - .digestKeyName(ENCRYPTION_KEY) - .data(SECRET_STRING) - .hmac(hmac)); - - res.send("Valid: " + verifyResponse.isValid()); - } - - private void verify(ServerRequest req, ServerResponse res) { - String signature = req.path().pathParameters().get("text"); - - Verify.Response verifyResponse = secrets.verify(Verify.Request.builder() - .digestKeyName(SIGNATURE_KEY) - .data(SECRET_STRING) - .signature(signature)); - - res.send("Valid: " + verifyResponse.isValid()); - } - - private void batch(ServerRequest req, ServerResponse res) { - String[] data = new String[]{"one", "two", "three", "four"}; - EncryptBatch.Request request = EncryptBatch.Request.builder() - .encryptionKeyName(ENCRYPTION_KEY); - DecryptBatch.Request decryptRequest = DecryptBatch.Request.builder() - .encryptionKeyName(ENCRYPTION_KEY); - - for (String item : data) { - request.addEntry(EncryptBatch.BatchEntry.create(Base64Value.create(item))); - } - List batchResult = secrets.encrypt(request).batchResult(); - for (Encrypt.Encrypted encrypted : batchResult) { - System.out.println("Encrypted: " + encrypted.cipherText()); - decryptRequest.addEntry(DecryptBatch.BatchEntry.create(encrypted.cipherText())); - } - - List base64Values = secrets.decrypt(decryptRequest).batchResult(); - for (int i = 0; i < data.length; i++) { - String decryptedValue = base64Values.get(i).toDecodedString(); - if (!data[i].equals(decryptedValue)) { - res.send("Data at index " + i + " is invalid. Decrypted " + decryptedValue - + ", expected: " + data[i]); - return; - } - } - res.send("Batch encryption/decryption completed"); - } -} diff --git a/examples/integrations/vault/hcp/src/main/java/io/helidon/examples/integrations/vault/hcp/VaultMain.java b/examples/integrations/vault/hcp/src/main/java/io/helidon/examples/integrations/vault/hcp/VaultMain.java deleted file mode 100644 index b4d6c11b8d3..00000000000 --- a/examples/integrations/vault/hcp/src/main/java/io/helidon/examples/integrations/vault/hcp/VaultMain.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.vault.hcp; - -import java.time.Duration; - -import io.helidon.config.Config; -import io.helidon.integrations.vault.Vault; -import io.helidon.integrations.vault.secrets.cubbyhole.CubbyholeSecrets; -import io.helidon.integrations.vault.secrets.kv1.Kv1Secrets; -import io.helidon.integrations.vault.secrets.kv2.Kv2Secrets; -import io.helidon.integrations.vault.secrets.transit.TransitSecrets; -import io.helidon.integrations.vault.sys.Sys; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.file; - -/** - * Main class of example. - */ -public final class VaultMain { - private VaultMain() { - } - - /** - * Main method of example. - * - * @param args ignored - */ - public static void main(String[] args) { - LogConfig.configureRuntime(); - - // as I cannot share my secret configuration, let's combine the configuration - // from my home directory with the one compiled into the jar - // when running this example, you can either update the application.yaml in resources directory - // or use the same approach - Config config = buildConfig(); - - // we have three configurations available - // 1. Token based authentication - Vault tokenVault = Vault.builder() - .config(config.get("vault.token")) - .updateWebClient(it -> it.connectTimeout(Duration.ofSeconds(5)) - .readTimeout(Duration.ofSeconds(5))) - .build(); - - // 2. App role based authentication - must be created after we obtain the role id an token - // 3. Kubernetes (k8s) based authentication (requires to run on k8s) - must be created after we create - // the authentication method - - // the tokenVault is using the root token and can be used to enable engines and - // other authentication mechanisms - - System.out.println(new K8sExample(tokenVault, config.get("vault.k8s")).run()); - System.out.println(new AppRoleExample(tokenVault, config.get("vault.approle")).run()); - - /* - We do not need to block here for our examples, as the server started below will keep the process running - */ - - Sys sys = tokenVault.sys(Sys.API); - // we use await for webserver, as we do not care if we block the main thread - it is not used - // for anything - WebServer webServer = WebServer.builder() - .config(config.get("server")) - .routing(routing -> routing - .register("/cubbyhole", new CubbyholeService(sys, tokenVault.secrets(CubbyholeSecrets.ENGINE))) - .register("/kv1", new Kv1Service(sys, tokenVault.secrets(Kv1Secrets.ENGINE))) - .register("/kv2", new Kv2Service(sys, tokenVault.secrets(Kv2Secrets.ENGINE))) - .register("/transit", new TransitService(sys, tokenVault.secrets(TransitSecrets.ENGINE)))) - .build() - .start(); - - String baseAddress = "http://localhost:" + webServer.port() + "/"; - System.out.println("Server started on " + baseAddress); - System.out.println(); - System.out.println("Key/Value Version 1 Secrets Engine"); - System.out.println("\t" + baseAddress + "kv1/enable"); - System.out.println("\t" + baseAddress + "kv1/create"); - System.out.println("\t" + baseAddress + "kv1/secrets/first/secret"); - System.out.println("\tcurl -i -X DELETE " + baseAddress + "kv1/secrets/first/secret"); - System.out.println("\t" + baseAddress + "kv1/disable"); - System.out.println(); - System.out.println("Key/Value Version 2 Secrets Engine"); - System.out.println("\t" + baseAddress + "kv2/create"); - System.out.println("\t" + baseAddress + "kv2/secrets/first/secret"); - System.out.println("\tcurl -i -X DELETE " + baseAddress + "kv2/secrets/first/secret"); - System.out.println(); - System.out.println("Transit Secrets Engine"); - System.out.println("\t" + baseAddress + "transit/enable"); - System.out.println("\t" + baseAddress + "transit/keys"); - System.out.println("\t" + baseAddress + "transit/encrypt/secret_text"); - System.out.println("\t" + baseAddress + "transit/decrypt/cipher_text"); - System.out.println("\t" + baseAddress + "transit/sign"); - System.out.println("\t" + baseAddress + "transit/verify/sign/signature_text"); - System.out.println("\t" + baseAddress + "transit/hmac"); - System.out.println("\t" + baseAddress + "transit/verify/hmac/hmac_text"); - System.out.println("\tcurl -i -X DELETE " + baseAddress + "transit/keys"); - System.out.println("\t" + baseAddress + "transit/disable"); - } - - private static Config buildConfig() { - return Config.builder() - .sources( - // you can use this file to override the defaults that are built-in - file(System.getProperty("user.home") + "/helidon/conf/examples.yaml").optional(), - // in jar file (see src/main/resources/application.yaml) - classpath("application.yaml")) - .build(); - } -} diff --git a/examples/integrations/vault/hcp/src/main/java/io/helidon/examples/integrations/vault/hcp/VaultPolicy.java b/examples/integrations/vault/hcp/src/main/java/io/helidon/examples/integrations/vault/hcp/VaultPolicy.java deleted file mode 100644 index 43b7cc0199a..00000000000 --- a/examples/integrations/vault/hcp/src/main/java/io/helidon/examples/integrations/vault/hcp/VaultPolicy.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.integrations.vault.hcp; - -final class VaultPolicy { - private VaultPolicy() { - } - static final String POLICY = "# Enable and manage authentication methods\n" - + "path \"auth/*\"\n" - + "{\n" - + " capabilities = [\"create\", \"update\", \"delete\", \"sudo\"]\n" - + "}\n" - + "\n" - + "# Create, update, and delete auth methods\n" - + "path \"sys/auth/*\"\n" - + "{\n" - + " capabilities = [\"create\", \"update\", \"delete\", \"sudo\"]\n" - + "}\n" - + "\n" - + "# List auth methods\n" - + "path \"sys/auth\"\n" - + "{\n" - + " capabilities = [\"read\"]\n" - + "}\n" - + "\n" - + "# Enable and manage the key/value secrets engine at `secret/` path\n" - + "\n" - + "# List, create, update, and delete key/value secrets\n" - + "path \"secret/*\"\n" - + "{\n" - + " capabilities = [\"create\", \"read\", \"update\", \"delete\", \"list\", \"sudo\"]\n" - + "}\n" - + "\n" - + "path \"kv1/*\"\n" - + "{\n" - + " capabilities = [\"create\", \"read\", \"update\", \"delete\", \"list\", \"sudo\"]\n" - + "}\n" - + "\n" - + "path \"cubbyhole/*\"\n" - + "{\n" - + " capabilities = [\"create\", \"read\", \"update\", \"delete\", \"list\", \"sudo\"]\n" - + "}\n" - + "\n" - + "path \"database/*\"\n" - + "{\n" - + " capabilities = [\"create\", \"read\", \"update\", \"delete\", \"list\", \"sudo\"]\n" - + "}\n" - + "\n" - + "path \"kv/*\"\n" - + "{\n" - + " capabilities = [\"create\", \"read\", \"update\", \"delete\", \"list\", \"sudo\"]\n" - + "}\n" - + "\n" - + "# Manage secrets engines\n" - + "path \"sys/mounts/*\"\n" - + "{\n" - + " capabilities = [\"create\", \"read\", \"update\", \"delete\", \"list\", \"sudo\"]\n" - + "}\n" - + "\n" - + "# List existing secrets engines.\n" - + "path \"sys/mounts\"\n" - + "{\n" - + " capabilities = [\"read\"]\n" - + "}\n"; -} diff --git a/examples/integrations/vault/hcp/src/main/java/io/helidon/examples/integrations/vault/hcp/package-info.java b/examples/integrations/vault/hcp/src/main/java/io/helidon/examples/integrations/vault/hcp/package-info.java deleted file mode 100644 index 20642d27a72..00000000000 --- a/examples/integrations/vault/hcp/src/main/java/io/helidon/examples/integrations/vault/hcp/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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 of Helidon integration with Hashicorp Vault. - */ -package io.helidon.examples.integrations.vault.hcp; diff --git a/examples/integrations/vault/hcp/src/main/resources/application.yaml b/examples/integrations/vault/hcp/src/main/resources/application.yaml deleted file mode 100644 index 6c42f51cce3..00000000000 --- a/examples/integrations/vault/hcp/src/main/resources/application.yaml +++ /dev/null @@ -1,59 +0,0 @@ -# -# Copyright (c) 2021, 2023 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 - -vault: - properties: - address: "http://localhost:8200" - k8s: - address: "${vault.properties.address}" - # please change this to your k8s cluster address - # cluster-address: "https://kubernetes.docker.internal:6443" - cluster-address: "https://10.96.0.1" - auth: - k8s: - enabled: true - # this role is created in the code, must be the same value - token-role: my-role - service-account-token: "${vault.properties.k8s.service-account-token}" - app-role: - enabled: false - token: - enabled: false - token: - token: "myroot" - address: "${vault.properties.address}" - auth: - k8s: - enabled: false - app-role: - enabled: false - token: - enabled: true - approle: - address: "${vault.properties.address}" - auth: - k8s: - enabled: false - app-role: - # this is not needed, as we use a builder, - # it is here to show how this could be used to define a - # custom path for vault authentication (same can be done for k8s) - path: "customapprole" - enabled: true - token: - enabled: false \ No newline at end of file diff --git a/examples/integrations/vault/hcp/src/main/resources/logging.properties b/examples/integrations/vault/hcp/src/main/resources/logging.properties deleted file mode 100644 index 341cef8ce9e..00000000000 --- a/examples/integrations/vault/hcp/src/main/resources/logging.properties +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright (c) 2021, 2023 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. -# - -# Send messages to the console -handlers=io.helidon.logging.jul.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 - -io.helidon.level=INFO -io.helidon.integrations.level=INFO diff --git a/examples/integrations/vault/pom.xml b/examples/integrations/vault/pom.xml deleted file mode 100644 index 632cb816475..00000000000 --- a/examples/integrations/vault/pom.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples.integrations - helidon-examples-integrations-project - 4.1.0-SNAPSHOT - - io.helidon.examples.integrations.vault - helidon-examples-integrations-vault-project - pom - Helidon Examples Integration Vault - Examples of integration with Vault. - - - hcp - hcp-cdi - - diff --git a/examples/jbatch/README.md b/examples/jbatch/README.md deleted file mode 100644 index 551fcdef8b3..00000000000 --- a/examples/jbatch/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Helidon + jBatch - -Minimal Helidon MP + jBatch PoC. - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-jbatch.jar -``` - -## Exercise the application - -```shell -curl -X GET http://localhost:8080/batch -``` \ No newline at end of file diff --git a/examples/jbatch/pom.xml b/examples/jbatch/pom.xml deleted file mode 100644 index 236d5255d2f..00000000000 --- a/examples/jbatch/pom.xml +++ /dev/null @@ -1,133 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../applications/mp/pom.xml - - io.helidon.examples.jbatch - helidon-examples-jbatch - Helidon Examples JBatch - - - 2.1.0 - 2.1.0 - 10.14.2.0 - 3.0.1 - - - - - io.helidon.microprofile.bundles - helidon-microprofile-core - - - io.helidon.logging - helidon-logging-jul - runtime - - - jakarta.json - jakarta.json-api - - - jakarta.transaction - jakarta.transaction-api - - - jakarta.batch - jakarta.batch-api - ${version.lib.jbatch-api} - - - com.ibm.jbatch - com.ibm.jbatch.spi - ${version.lib.jbatch.container} - - - org.glassfish.jaxb - jaxb-runtime - ${version.lib.jaxb-api} - - - - - io.smallrye - jandex - runtime - true - - - com.ibm.jbatch - com.ibm.jbatch.container - ${version.lib.jbatch.container} - runtime - - - org.apache.derby - derby - ${version.lib.derby} - runtime - - - - org.junit.jupiter - junit-jupiter-api - test - - - io.helidon.microprofile.testing - helidon-microprofile-testing-junit5 - test - - - org.hamcrest - hamcrest-core - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/jbatch/src/main/java/io/helidon/examples/jbatch/BatchResource.java b/examples/jbatch/src/main/java/io/helidon/examples/jbatch/BatchResource.java deleted file mode 100644 index dd7d2aaa3c0..00000000000 --- a/examples/jbatch/src/main/java/io/helidon/examples/jbatch/BatchResource.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.jbatch; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Properties; - -import com.ibm.jbatch.spi.BatchSPIManager; -import jakarta.batch.operations.JobOperator; -import jakarta.batch.runtime.JobExecution; -import jakarta.batch.runtime.StepExecution; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -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 static jakarta.batch.runtime.BatchRuntime.getJobOperator; - - -/** - * Trigger a batch process using resource. - */ -@Path("/batch") -@ApplicationScoped -public class BatchResource { - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - private JobOperator jobOperator; - - /** - * Run a JBatch process when endpoint called. - * @return JsonObject with the result. - */ - @GET - @Produces(MediaType.APPLICATION_JSON) - public JsonObject executeBatch() { - - BatchSPIManager batchSPIManager = BatchSPIManager.getInstance(); - batchSPIManager.registerPlatformMode(BatchSPIManager.PlatformMode.SE); - batchSPIManager.registerExecutorServiceProvider(new HelidonExecutorServiceProvider()); - - jobOperator = getJobOperator(); - Long executionId = jobOperator.start("myJob", new Properties()); - - return JSON.createObjectBuilder() - .add("Started a job with Execution ID: ", executionId) - .build(); - } - - /** - * Check the job status. - * @param executionId the job ID. - * @return JsonObject with status. - */ - @GET - @Path("/status/{execution-id}") - public JsonObject status(@PathParam("execution-id") Long executionId){ - JobExecution jobExecution = jobOperator.getJobExecution(executionId); - - List stepExecutions = jobOperator.getStepExecutions(executionId); - List executedSteps = new ArrayList<>(); - for (StepExecution stepExecution : stepExecutions) { - executedSteps.add(stepExecution.getStepName()); - } - - return JSON.createObjectBuilder() - .add("Steps executed", Arrays.toString(executedSteps.toArray())) - .add("Status", jobExecution.getBatchStatus().toString()) - .build(); - } -} diff --git a/examples/jbatch/src/main/java/io/helidon/examples/jbatch/HelidonExecutorServiceProvider.java b/examples/jbatch/src/main/java/io/helidon/examples/jbatch/HelidonExecutorServiceProvider.java deleted file mode 100644 index 81ae527218e..00000000000 --- a/examples/jbatch/src/main/java/io/helidon/examples/jbatch/HelidonExecutorServiceProvider.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.jbatch; - -import java.util.concurrent.ExecutorService; - -import io.helidon.common.configurable.ThreadPoolSupplier; - -import com.ibm.jbatch.spi.ExecutorServiceProvider; - - -/** - * Executor service for batch processing. - */ -public class HelidonExecutorServiceProvider implements ExecutorServiceProvider { - @Override - public ExecutorService getExecutorService() { - return ThreadPoolSupplier.builder().corePoolSize(2).build().get(); - } -} diff --git a/examples/jbatch/src/main/java/io/helidon/examples/jbatch/jobs/MyBatchlet.java b/examples/jbatch/src/main/java/io/helidon/examples/jbatch/jobs/MyBatchlet.java deleted file mode 100644 index f430b6dfa02..00000000000 --- a/examples/jbatch/src/main/java/io/helidon/examples/jbatch/jobs/MyBatchlet.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.jbatch.jobs; - -import jakarta.batch.api.AbstractBatchlet; - -/** - * Batchlet example. - */ -public class MyBatchlet extends AbstractBatchlet { - - /** - * Run inside a batchlet. - * - * @return String with status. - */ - @Override - public String process() { - System.out.println("Running inside a batchlet"); - return "COMPLETED"; - } - -} diff --git a/examples/jbatch/src/main/java/io/helidon/examples/jbatch/jobs/MyInputRecord.java b/examples/jbatch/src/main/java/io/helidon/examples/jbatch/jobs/MyInputRecord.java deleted file mode 100644 index 65e59b4fcc4..00000000000 --- a/examples/jbatch/src/main/java/io/helidon/examples/jbatch/jobs/MyInputRecord.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.jbatch.jobs; - -/** - * Example of an Input Record. - */ -public class MyInputRecord { - private int id; - - /** - * Constructor for Input Record. - * @param id - */ - public MyInputRecord(int id) { - this.id = id; - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - @Override - public String toString() { - return "MyInputRecord: " + id; - } -} diff --git a/examples/jbatch/src/main/java/io/helidon/examples/jbatch/jobs/MyItemProcessor.java b/examples/jbatch/src/main/java/io/helidon/examples/jbatch/jobs/MyItemProcessor.java deleted file mode 100644 index a57516d36c5..00000000000 --- a/examples/jbatch/src/main/java/io/helidon/examples/jbatch/jobs/MyItemProcessor.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.jbatch.jobs; - -import jakarta.batch.api.chunk.ItemProcessor; - -/** - * Example Item Processor. - */ -public class MyItemProcessor implements ItemProcessor { - - @Override - public MyOutputRecord processItem(Object t) { - System.out.println("processItem: " + t); - - return (((MyInputRecord) t).getId() % 2 == 0) ? null : new MyOutputRecord(((MyInputRecord) t).getId() * 2); - } -} diff --git a/examples/jbatch/src/main/java/io/helidon/examples/jbatch/jobs/MyItemReader.java b/examples/jbatch/src/main/java/io/helidon/examples/jbatch/jobs/MyItemReader.java deleted file mode 100644 index daad53e70a4..00000000000 --- a/examples/jbatch/src/main/java/io/helidon/examples/jbatch/jobs/MyItemReader.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.jbatch.jobs; - -import java.util.StringTokenizer; - -import jakarta.batch.api.chunk.AbstractItemReader; - - -/** - * Example Item Reader. - */ -public class MyItemReader extends AbstractItemReader { - - private final StringTokenizer tokens; - - /** - * Constructor for Item Reader. - */ - public MyItemReader() { - tokens = new StringTokenizer("1,2,3,4,5,6,7,8,9,10", ","); - } - - /** - * Perform read Item. - * @return Stage result. - */ - @Override - public MyInputRecord readItem() { - if (tokens.hasMoreTokens()) { - return new MyInputRecord(Integer.valueOf(tokens.nextToken())); - } - return null; - } -} diff --git a/examples/jbatch/src/main/java/io/helidon/examples/jbatch/jobs/MyItemWriter.java b/examples/jbatch/src/main/java/io/helidon/examples/jbatch/jobs/MyItemWriter.java deleted file mode 100644 index a4806af09f1..00000000000 --- a/examples/jbatch/src/main/java/io/helidon/examples/jbatch/jobs/MyItemWriter.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.jbatch.jobs; - -import java.util.List; - -import jakarta.batch.api.chunk.AbstractItemWriter; - - -/** - * Example Item Writer. - */ -public class MyItemWriter extends AbstractItemWriter { - - @Override - public void writeItems(List list) { - System.out.println("writeItems: " + list); - } -} diff --git a/examples/jbatch/src/main/java/io/helidon/examples/jbatch/jobs/MyOutputRecord.java b/examples/jbatch/src/main/java/io/helidon/examples/jbatch/jobs/MyOutputRecord.java deleted file mode 100644 index 09a751c0ed5..00000000000 --- a/examples/jbatch/src/main/java/io/helidon/examples/jbatch/jobs/MyOutputRecord.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.jbatch.jobs; - -/** - * Example Output Processor. - */ -public class MyOutputRecord { - - private int id; - - /** - * Constructor for Output Record. - * @param id - */ - public MyOutputRecord(int id) { - this.id = id; - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - @Override - public String toString() { - return "MyOutputRecord: " + id; - } -} diff --git a/examples/jbatch/src/main/java/io/helidon/examples/jbatch/jobs/package-info.java b/examples/jbatch/src/main/java/io/helidon/examples/jbatch/jobs/package-info.java deleted file mode 100644 index 406c301f930..00000000000 --- a/examples/jbatch/src/main/java/io/helidon/examples/jbatch/jobs/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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. - */ - -/** - * JBatch specific classes. - */ -package io.helidon.examples.jbatch.jobs; diff --git a/examples/jbatch/src/main/java/io/helidon/examples/jbatch/package-info.java b/examples/jbatch/src/main/java/io/helidon/examples/jbatch/package-info.java deleted file mode 100644 index a7921e38241..00000000000 --- a/examples/jbatch/src/main/java/io/helidon/examples/jbatch/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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 application showing support for JBatch and HelidonMP. - */ -package io.helidon.examples.jbatch; diff --git a/examples/jbatch/src/main/resources/META-INF/batch-jobs/myJob.xml b/examples/jbatch/src/main/resources/META-INF/batch-jobs/myJob.xml deleted file mode 100644 index 4788e859b2b..00000000000 --- a/examples/jbatch/src/main/resources/META-INF/batch-jobs/myJob.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/examples/jbatch/src/main/resources/META-INF/beans.xml b/examples/jbatch/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 0de0bc4f151..00000000000 --- a/examples/jbatch/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/jbatch/src/main/resources/META-INF/helidon/serial-config.properties b/examples/jbatch/src/main/resources/META-INF/helidon/serial-config.properties deleted file mode 100644 index 8aad930d0ed..00000000000 --- a/examples/jbatch/src/main/resources/META-INF/helidon/serial-config.properties +++ /dev/null @@ -1,19 +0,0 @@ -# -# 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. -# - -# The JBatch uses Serialization a lot, and these are all required -pattern=com.ibm.jbatch.**;jakarta.batch.runtime.BatchStatus;java.lang.Enum;\ - java.util.Properties;java.util.Hashtable;java.util.Map$Entry diff --git a/examples/jbatch/src/main/resources/META-INF/microprofile-config.properties b/examples/jbatch/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 52cd57f8f73..00000000000 --- a/examples/jbatch/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,22 +0,0 @@ -# -# 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. -# - -# 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 diff --git a/examples/jbatch/src/main/resources/logging.properties b/examples/jbatch/src/main/resources/logging.properties deleted file mode 100644 index b5e2c644b3d..00000000000 --- a/examples/jbatch/src/main/resources/logging.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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 diff --git a/examples/jbatch/src/test/java/io/helidon/examples/jbatch/TestJBatchEndpoint.java b/examples/jbatch/src/test/java/io/helidon/examples/jbatch/TestJBatchEndpoint.java deleted file mode 100644 index dfbf82390f7..00000000000 --- a/examples/jbatch/src/test/java/io/helidon/examples/jbatch/TestJBatchEndpoint.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.jbatch; - -import java.util.Collections; - -import io.helidon.microprofile.testing.junit5.HelidonTest; - -import jakarta.inject.Inject; -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.MediaType; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.MatcherAssert.assertThat; - -@HelidonTest -public class TestJBatchEndpoint { - - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - @Inject - private WebTarget webTarget; - - @Test - public void runJob() throws InterruptedException { - - JsonObject expectedJson = JSON.createObjectBuilder() - .add("Steps executed", "[step1, step2]") - .add("Status", "COMPLETED") - .build(); - - //Start the job - JsonObject jsonObject = webTarget - .path("/batch") - .request(MediaType.APPLICATION_JSON_TYPE) - .get(JsonObject.class); - - Integer responseJobId = jsonObject.getInt("Started a job with Execution ID: "); - assertThat(responseJobId, is(notNullValue())); - JsonObject result = null; - for (int i = 1; i < 10; i++) { - //Wait a bit for it to complete - Thread.sleep(i*1000); - - //Examine the results - result = webTarget - .path("batch/status/" + responseJobId) - .request(MediaType.APPLICATION_JSON_TYPE) - .get(JsonObject.class); - - if (result.equals(expectedJson)){ - break; - } - - } - - assertThat(result, equalTo(expectedJson)); - } -} diff --git a/examples/k8s/zipkin.yaml b/examples/k8s/zipkin.yaml deleted file mode 100644 index 8785b945c2d..00000000000 --- a/examples/k8s/zipkin.yaml +++ /dev/null @@ -1,73 +0,0 @@ -# -# Copyright (c) 2019, 2021 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. -# - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: zipkin - labels: - app: zipkin -spec: - selector: - matchLabels: - app: zipkin - replicas: 1 - template: - metadata: - labels: - app: zipkin - spec: - containers: - - name: zipkin - image: openzipkin/zipkin:2 - imagePullPolicy: Always - ports: - - containerPort: 9411 ---- - -apiVersion: v1 -kind: Service -metadata: - name: zipkin - labels: - app: zipkin -spec: - type: ClusterIP - selector: - app: zipkin - ports: - - port: 9411 - targetPort: 9411 - name: http - ---- - -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: zipkin-ingress -spec: - rules: - - host: localhost - http: - paths: - - path: /zipkin - pathType: Prefix - backend: - service: - name: zipkin - port: - number: 9411 diff --git a/examples/logging/jul/README.md b/examples/logging/jul/README.md deleted file mode 100644 index 44a10a6a2b9..00000000000 --- a/examples/logging/jul/README.md +++ /dev/null @@ -1,52 +0,0 @@ -JUL Example ---- - -This example shows how to use Java Util Logging with MDC - using Helidon API. - -The example can be built using GraalVM native image as well. - -# Running as jar - -Build this application: -```shell -mvn clean package -``` - -Run from command line: -```shell -java -jar target/helidon-examples-logging-jul.jar -``` - -Expected output should be similar to the following: -```text -2020.11.19 15:37:28 INFO io.helidon.logging.jul.JulProvider Thread[#1,main,5,main]: Logging at initialization configured using classpath: /logging.properties "" -2020.11.19 15:37:28 INFO io.helidon.examples.logging.jul.Main Thread[main,5,main]: Starting up "startup" -2020.11.19 15:37:28 INFO io.helidon.examples.logging.jul.Main Thread[pool-1-thread-1,5,main]: Running on another thread "propagated" -2020.11.19 15:37:28 INFO io.helidon.common.features.HelidonFeatures Thread[#23,features-thread,5,main]: Helidon 4.0.0-SNAPSHOT features: [Config, Encoding, Media, WebServer] "" -2020.11.19 15:37:28 INFO io.helidon.webserver.LoomServer Thread[#1,main,5,main]: Started all channels in 46 milliseconds. 577 milliseconds since JVM startup. Java 20.0.1+9-29 "propagated" -``` - -# Running as native image -You must use GraalVM with native image installed as your JDK, -or you can specify an environment variable `GRAALVM_HOME` that points -to such an installation. - -Build this application: -```shell -mvn clean package -Pnative-image -``` - -Run from command line: -```shell -./target/helidon-examples-logging-jul -``` - -Expected output should be similar to the following: -```text -2020.11.19 15:38:14 INFO io.helidon.logging.common.LogConfig Thread[main,5,main]: Logging at runtime configured using classpath: /logging.properties "" -2020.11.19 15:38:14 INFO io.helidon.examples.logging.jul.Main Thread[main,5,main]: Starting up "startup" -2020.11.19 15:38:14 INFO io.helidon.examples.logging.jul.Main Thread[pool-1-thread-1,5,main]: Running on another thread "propagated" -2020.11.19 15:38:14 INFO io.helidon.common.features.HelidonFeatures Thread[features-thread,5,main]: Helidon SE 2.2.0 features: [Config, WebServer] "" -2020.11.19 15:38:14 INFO io.helidon.reactive.webserver.NettyWebServer Thread[nioEventLoopGroup-2-1,10,main]: Channel '@default' started: [id: 0x2b929906, L:/0:0:0:0:0:0:0:0:8080] "" -``` \ No newline at end of file diff --git a/examples/logging/jul/pom.xml b/examples/logging/jul/pom.xml deleted file mode 100644 index 57877d18907..00000000000 --- a/examples/logging/jul/pom.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.logging - helidon-examples-logging-jul - Helidon Examples Logging Java Util Logging - - - Example of logging and MDC using JUL - - - - io.helidon.examples.logging.jul.Main - - - - - io.helidon.webserver - helidon-webserver - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/logging/jul/src/main/java/io/helidon/examples/logging/jul/Main.java b/examples/logging/jul/src/main/java/io/helidon/examples/logging/jul/Main.java deleted file mode 100644 index e6b6285644b..00000000000 --- a/examples/logging/jul/src/main/java/io/helidon/examples/logging/jul/Main.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.logging.jul; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.logging.Logger; - -import io.helidon.common.context.Context; -import io.helidon.common.context.Contexts; -import io.helidon.logging.common.HelidonMdc; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.http.HttpRouting; - -/** - * Main class of the example, runnable from command line. - */ -public final class Main { - private static final Logger LOGGER = Logger.getLogger(Main.class.getName()); - - private Main() { - } - - /** - * Starts the example. - * - * @param args not used - */ - public static void main(String[] args) { - LogConfig.configureRuntime(); - - // the Helidon context is used to propagate MDC across threads - // if running within Helidon WebServer, you do not need to runInContext, as that is already - // done by the webserver - Contexts.runInContext(Context.create(), Main::logging); - - WebServer server = WebServer.builder() - .port(8080) - .routing(Main::routing) - .build() - .start(); - } - - private static void routing(HttpRouting.Builder routing) { - routing.get("/", (req, res) -> { - HelidonMdc.set("name", String.valueOf(req.id())); - LOGGER.info("Running in webserver, id:"); - res.send("Hello"); - }); - } - - private static void logging() { - HelidonMdc.set("name", "startup"); - LOGGER.info("Starting up"); - - // now let's see propagation across executor service boundary - HelidonMdc.set("name", "propagated"); - // wrap executor so it supports Helidon context, this is done for all built-in executors in Helidon - ExecutorService es = Contexts.wrap(Executors.newSingleThreadExecutor()); - - Future submit = es.submit(() -> { - LOGGER.info("Running on another thread"); - }); - try { - submit.get(); - } catch (Exception e) { - e.printStackTrace(); - } - es.shutdown(); - } -} diff --git a/examples/logging/jul/src/main/java/io/helidon/examples/logging/jul/package-info.java b/examples/logging/jul/src/main/java/io/helidon/examples/logging/jul/package-info.java deleted file mode 100644 index 250b9a7dc4b..00000000000 --- a/examples/logging/jul/src/main/java/io/helidon/examples/logging/jul/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020 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. - */ - -/** - * Java util logging example with Mapped diagnostics context in Helidon. - */ -package io.helidon.examples.logging.jul; diff --git a/examples/logging/jul/src/main/resources/logging.properties b/examples/logging/jul/src/main/resources/logging.properties deleted file mode 100644 index 3cb6b545c53..00000000000 --- a/examples/logging/jul/src/main/resources/logging.properties +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2020 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. -# - -# Send messages to the console -handlers=io.helidon.logging.jul.HelidonConsoleHandler - -# !thread! is replaced by Helidon with the thread name -# any %X{...} is replaced by a value from MDC -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 "%X{name}"%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO diff --git a/examples/logging/log4j/README.md b/examples/logging/log4j/README.md deleted file mode 100644 index bf7f618921f..00000000000 --- a/examples/logging/log4j/README.md +++ /dev/null @@ -1,55 +0,0 @@ -Log4j Example ---- - -This example shows how to use log4j with MDC (`ThreadContext`) - using Helidon API. - -The example moves all Java Util Logging to log4j. - -The example can be built using GraalVM native image as well. - -# Running as jar - -Build this application: -```shell -mvn clean package -``` - -Run from command line: -```shell -java -jar target/helidon-examples-logging-log4j.jar -``` - -Expected output should be similar to the following: -```text -15:44:48.596 INFO [main] io.helidon.examples.logging.log4j.Main - Starting up "startup" -15:44:48.598 INFO [main] io.helidon.examples.logging.log4j.Main - Using System logger "startup" -15:44:48.600 INFO [pool-2-thread-1] io.helidon.examples.logging.log4j.Main - Running on another thread "propagated" -15:44:48.704 INFO [features-thread] io.helidon.common.features.HelidonFeatures - Helidon 4.0.0-SNAPSHOT features: [Config, Encoding, Media, WebServer] "" -15:44:48.801 INFO [main] io.helidon.webserver.LoomServer - Started all channels in 12 milliseconds. 746 milliseconds since JVM startup. Java 20.0.1+9-29 "propagated" -``` - -# Running as native image -You must use GraalVM with native image installed as your JDK, -or you can specify an environment variable `GRAALVM_HOME` that points -to such an installation. - -Build this application: -```shell -mvn clean package -Pnative-image -``` - -Run from command line: -```shell -./target/helidon-examples-logging-log4j -``` - -*In native image, we can only replace loggers initialized after reconfiguration of logging system -This unfortunately means that Helidon logging would not be available* - -Expected output should be similar to the following: -```text -15:47:53.033 INFO [main] io.helidon.examples.logging.log4j.Main - Starting up "startup" -15:47:53.033 INFO [main] io.helidon.examples.logging.log4j.Main - Using JUL logger "startup" -15:47:53.033 INFO [pool-2-thread-1] io.helidon.examples.logging.log4j.Main - Running on another thread "propagated" -``` \ No newline at end of file diff --git a/examples/logging/log4j/pom.xml b/examples/logging/log4j/pom.xml deleted file mode 100644 index 70efd046428..00000000000 --- a/examples/logging/log4j/pom.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.logging - helidon-examples-logging-log4j - Helidon Examples Logging Log4j - - - Example of logging and MDC using Log4j - - - - io.helidon.examples.logging.log4j.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.logging - helidon-logging-log4j - - - org.apache.logging.log4j - log4j-api - - - org.apache.logging.log4j - log4j-core - - - org.apache.logging.log4j - log4j-jul - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/logging/log4j/src/main/java/io/helidon/examples/logging/log4j/Main.java b/examples/logging/log4j/src/main/java/io/helidon/examples/logging/log4j/Main.java deleted file mode 100644 index 9b4ac0a5aae..00000000000 --- a/examples/logging/log4j/src/main/java/io/helidon/examples/logging/log4j/Main.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.logging.log4j; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - -import io.helidon.common.context.Context; -import io.helidon.common.context.Contexts; -import io.helidon.logging.common.HelidonMdc; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.http.HttpRouting; - -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.ThreadContext; -import org.apache.logging.log4j.core.appender.ConsoleAppender; -import org.apache.logging.log4j.core.config.Configurator; -import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory; - -/** - * Main class of the example, runnable from command line. - * There is a limitation of log4j in native image - we only have loggers that are - * initialized after we configure logging, which unfortunately excludes Helidon loggers. - * You would need to use JUL or slf4j to have Helidon logs combined with application logs. - */ -public final class Main { - private static System.Logger systemLogger; - private static Logger logger; - - private Main() { - } - - /** - * Starts the example. - * - * @param args not used - */ - public static void main(String[] args) { - // file based logging configuration does not work - // with native image! - configureLog4j(); - LogConfig.configureRuntime(); - // get logger after configuration - logger = LogManager.getLogger(Main.class); - systemLogger = System.getLogger(Main.class.getName()); - - // the Helidon context is used to propagate MDC across threads - // if running within Helidon WebServer, you do not need to runInContext, as that is already - // done by the webserver - Contexts.runInContext(Context.create(), Main::logging); - - WebServer server = WebServer.builder() - .routing(Main::routing) - .build() - .start(); - } - - private static void routing(HttpRouting.Builder routing) { - routing.get("/", (req, res) -> { - HelidonMdc.set("name", String.valueOf(req.id())); - logger.info("Running in webserver, id:"); - res.send("Hello"); - }); - } - - private static void logging() { - HelidonMdc.set("name", "startup"); - logger.info("Starting up"); - systemLogger.log(System.Logger.Level.INFO, "Using System logger"); - - // now let's see propagation across executor service boundary, we can also use Log4j's ThreadContext - ThreadContext.put("name", "propagated"); - // wrap executor so it supports Helidon context, this is done for all built-in executors in Helidon - ExecutorService es = Contexts.wrap(Executors.newSingleThreadExecutor()); - - Future submit = es.submit(Main::log); - try { - submit.get(); - } catch (Exception e) { - e.printStackTrace(); - } - es.shutdown(); - } - - private static void log() { - logger.info("Running on another thread"); - } - - private static void configureLog4j() { - // configure log4j - final var builder = ConfigurationBuilderFactory.newConfigurationBuilder(); - builder.setConfigurationName("root"); - builder.setStatusLevel(Level.INFO); - final var appenderComponentBuilder = builder.newAppender("Stdout", "CONSOLE") - .addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT); - appenderComponentBuilder.add(builder.newLayout("PatternLayout") - .addAttribute("pattern", "%d{HH:mm:ss.SSS} %-5level [%t] %logger{36} - %msg " - + "\"%X{name}\"%n")); - builder.add(appenderComponentBuilder); - builder.add(builder.newRootLogger(Level.INFO) - .add(builder.newAppenderRef("Stdout"))); - Configurator.initialize(builder.build()); - } -} diff --git a/examples/logging/log4j/src/main/java/io/helidon/examples/logging/log4j/package-info.java b/examples/logging/log4j/src/main/java/io/helidon/examples/logging/log4j/package-info.java deleted file mode 100644 index 2315e1b7116..00000000000 --- a/examples/logging/log4j/src/main/java/io/helidon/examples/logging/log4j/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020 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. - */ - -/** - * Log4j example with Mapped diagnostics context (ThreadContext) in Helidon. - */ -package io.helidon.examples.logging.log4j; diff --git a/examples/logging/logback-aot/README.md b/examples/logging/logback-aot/README.md deleted file mode 100644 index 1ba544c0b3c..00000000000 --- a/examples/logging/logback-aot/README.md +++ /dev/null @@ -1,60 +0,0 @@ -Slf4j/Logback Example ---- - -This example shows how to use slf4j with MDC backed by Logback - using Helidon API. - -The example moves all Java Util Logging to slf4j and supports more advance configuration of logback. - -# AOT (native image) -To support native image, we need to use a different logback configuration at build time and at runtime. -To achieve this, we bundle `logback.xml` on classpath, and then have `logback-runtime.xml` with -configuration that requires started threads (which is not supported at build time). - -The implementation will re-configure logback (see method `setupLogging` in `Main.java). - -To see that configuration works as expected at runtime, change the log level of our package to `debug`. -Within 30 seconds the configuration should be reloaded, and next request will have two more debug messages. - -Expected output should be similar to the following (for both hotspot and native): -```text -15:40:44.240 [INFO ] [io.helidon.examples.logging.logback.aot.Main.logging:128] Starting up startup -15:40:44.241 [INFO ] [o.slf4j.jdk.platform.logging.SLF4JPlatformLogger.performLog:151] Using System logger startup -15:40:44.245 [INFO ] [io.helidon.examples.logging.logback.aot.Main.log:146] Running on another thread propagated -15:40:44.395 [INFO ] [o.slf4j.jdk.platform.logging.SLF4JPlatformLogger.performLog:151] Helidon 4.0.0-SNAPSHOT features: [Config, Encoding, Media, WebServer] -15:40:44.538 [INFO ] [o.slf4j.jdk.platform.logging.SLF4JPlatformLogger.performLog:151] Started all channels in 15 milliseconds. 647 milliseconds since JVM startup. Java 20.0.1+9-29 propagated -``` - -The output is also logged into `helidon.log`. - -# Running as jar - -Build this application: -```shell -mvn clean package -``` - -Run from command line: -```shell -java -jar target/helidon-examples-logging-slf4j-aot.jar -``` - -Execute endpoint: -```shell -curl -i http://localhost:8080 -``` - -# Running as native image -You must use GraalVM with native image installed as your JDK, -or you can specify an environment variable `GRAALVM_HOME` that points -to such an installation. - -Build this application: -```shell script -mvn clean package -Pnative-image -``` - -Run from command line: -```shell -./target/helidon-examples-logging-slf4j-aot -``` diff --git a/examples/logging/logback-aot/logback-runtime.xml b/examples/logging/logback-aot/logback-runtime.xml deleted file mode 100644 index c700ab33a24..00000000000 --- a/examples/logging/logback-aot/logback-runtime.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - helidon.log - true - false - - helidon.%d{yyyy-MM-dd}.gz - 10 - 5GB - - - - ${defaultPattern} - - - - - - 2048 - 15000 - true - true - - - - - ${defaultPattern} - - - - - - - - - - - - - - - diff --git a/examples/logging/logback-aot/pom.xml b/examples/logging/logback-aot/pom.xml deleted file mode 100644 index 7b85fea9c4f..00000000000 --- a/examples/logging/logback-aot/pom.xml +++ /dev/null @@ -1,79 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.logging - helidon-examples-logging-slf4j-aot - Helidon Examples Logging Slf4j AOT - - - Example of logging and MDC using Slf4j ready for Ahead of time compilation - using GraalVM native image - - - - io.helidon.examples.logging.logback.aot.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.logging - helidon-logging-slf4j - - - org.slf4j - slf4j-api - - - org.slf4j - jul-to-slf4j - - - ch.qos.logback - logback-classic - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/logging/logback-aot/src/main/java/io/helidon/examples/logging/logback/aot/Main.java b/examples/logging/logback-aot/src/main/java/io/helidon/examples/logging/logback/aot/Main.java deleted file mode 100644 index 45c833374b5..00000000000 --- a/examples/logging/logback-aot/src/main/java/io/helidon/examples/logging/logback/aot/Main.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.logging.logback.aot; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - -import io.helidon.common.context.Context; -import io.helidon.common.context.Contexts; -import io.helidon.logging.common.HelidonMdc; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.http.HttpRouting; - -import ch.qos.logback.classic.LoggerContext; -import ch.qos.logback.classic.joran.JoranConfigurator; -import ch.qos.logback.core.joran.spi.JoranException; -import ch.qos.logback.core.util.StatusPrinter; -import org.slf4j.ILoggerFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.slf4j.MDC; - -/** - * Main class of the example, runnable from command line. - */ -public final class Main { - private static final Logger LOGGER = LoggerFactory.getLogger(Main.class); - private static final System.Logger SYSTEM_LOGGER = System.getLogger(Main.class.getName()); - - private Main() { - } - - /** - * Starts the example. - * - * @param args not used - */ - public static void main(String[] args) { - // use slf4j for JUL as well - setupLogging(); - - // the Helidon context is used to propagate MDC across threads - // if running within Helidon WebServer, you do not need to runInContext, as that is already - // done by the webserver - Contexts.runInContext(Context.create(), Main::logging); - - WebServer server = WebServer.builder() - .port(8080) - .routing(Main::routing) - .build() - .start(); - } - - private static void routing(HttpRouting.Builder routing) { - routing.get("/", (req, res) -> { - HelidonMdc.set("name", String.valueOf(req.id())); - LOGGER.debug("Debug message to show runtime reloading works"); - LOGGER.info("Running in webserver, id:"); - res.send("Hello"); - LOGGER.debug("Response sent"); - }); - } - - private static void setupLogging() { - String location = System.getProperty("logback.configurationFile"); - location = (location == null) ? "logback-runtime.xml" : location; - // we cannot use anything that starts threads at build time, must re-configure here - resetLogging(location); - } - - private static void resetLogging(String location) { - ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory(); - if (loggerFactory instanceof LoggerContext) { - resetLogging(location, (LoggerContext) loggerFactory); - } else { - LOGGER.warn("Expecting a logback implementation, but got " + loggerFactory.getClass().getName()); - } - } - - private static void resetLogging(String location, LoggerContext loggerFactory) { - JoranConfigurator configurator = new JoranConfigurator(); - - configurator.setContext(loggerFactory); - loggerFactory.reset(); - - try { - configurator.doConfigure(location); - - Logger instance = LoggerFactory.getLogger(Main.class); - instance.info("Runtime logging configured from file \"{}\".", location); - StatusPrinter.print(loggerFactory); - } catch (JoranException e) { - LOGGER.warn("Failed to reload logging from " + location, e); - e.printStackTrace(); - } - } - - private static void logging() { - HelidonMdc.set("name", "startup"); - LOGGER.info("Starting up"); - SYSTEM_LOGGER.log(System.Logger.Level.INFO, "Using System logger"); - - // now let's see propagation across executor service boundary, we can also use Log4j's ThreadContext - MDC.put("name", "propagated"); - // wrap executor so it supports Helidon context, this is done for all built-in executors in Helidon - ExecutorService es = Contexts.wrap(Executors.newSingleThreadExecutor()); - - Future submit = es.submit(Main::log); - try { - submit.get(); - } catch (Exception e) { - e.printStackTrace(); - } - es.shutdown(); - } - - private static void log() { - LOGGER.info("Running on another thread"); - } -} diff --git a/examples/logging/logback-aot/src/main/java/io/helidon/examples/logging/logback/aot/package-info.java b/examples/logging/logback-aot/src/main/java/io/helidon/examples/logging/logback/aot/package-info.java deleted file mode 100644 index 9094294a35a..00000000000 --- a/examples/logging/logback-aot/src/main/java/io/helidon/examples/logging/logback/aot/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2021 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. - */ - -/** - * Slf4j example with Mapped diagnostics context (MDC) in Helidon ready for - * complex runtime configuration in native image. - */ -package io.helidon.examples.logging.logback.aot; diff --git a/examples/logging/logback-aot/src/main/resources/logback.xml b/examples/logging/logback-aot/src/main/resources/logback.xml deleted file mode 100644 index db7f4e49578..00000000000 --- a/examples/logging/logback-aot/src/main/resources/logback.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - %d{HH:mm:ss.SSS} %-5level [%thread] %logger{36} - %msg %X{name}%n - - - - - - - - \ No newline at end of file diff --git a/examples/logging/pom.xml b/examples/logging/pom.xml deleted file mode 100644 index 7a2d1be6c44..00000000000 --- a/examples/logging/pom.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples - helidon-examples-project - 4.1.0-SNAPSHOT - - io.helidon.examples.logging - helidon-examples-logging-project - Helidon Examples Logging - pom - - - Examples of Helidon Logging - - - - jul - log4j - slf4j - logback-aot - - diff --git a/examples/logging/slf4j/README.md b/examples/logging/slf4j/README.md deleted file mode 100644 index 7ef0fcd5ca7..00000000000 --- a/examples/logging/slf4j/README.md +++ /dev/null @@ -1,45 +0,0 @@ -Slf4j Example ---- - -This example shows how to use slf4j with MDC - using Helidon API. - -The example moves all Java Util Logging to slf4j - -The example can be built using GraalVM native image as well. - -Expected output should be similar to the following (for both hotspot and native): -```text -15:40:44.240 INFO [main] i.h.examples.logging.slf4j.Main - Starting up startup -15:40:44.241 INFO [main] i.h.examples.logging.slf4j.Main - Using System logger startup -15:40:44.245 INFO [pool-1-thread-1] i.h.examples.logging.slf4j.Main - Running on another thread propagated -15:40:44.395 INFO [features-thread] i.h.common.features.HelidonFeatures - Helidon 4.0.0-SNAPSHOT features: [Config, Encoding, Media, WebServer] -15:40:44.538 INFO [main] i.helidon.webserver.LoomServer - Started all channels in 15 milliseconds. 561 milliseconds since JVM startup. Java 20.0.1+9-29 propagated -``` - -# Running as jar - -Build this application: -```shell -mvn clean package -``` - -Run from command line: -```shell -java -jar target/helidon-examples-logging-slf4j.jar -``` - -# Running as native image -You must use GraalVM with native image installed as your JDK, -or you can specify an environment variable `GRAALVM_HOME` that points -to such an installation. - -Build this application: -```shell -mvn clean package -Pnative-image -``` - -Run from command line: -```shell -./target/helidon-examples-logging-slf4j -``` \ No newline at end of file diff --git a/examples/logging/slf4j/pom.xml b/examples/logging/slf4j/pom.xml deleted file mode 100644 index 1693c199980..00000000000 --- a/examples/logging/slf4j/pom.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.logging - helidon-examples-logging-slf4j - Helidon Examples Logging Slf4j - - - Example of logging and MDC using Slf4j - - - - io.helidon.examples.logging.slf4j.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.logging - helidon-logging-slf4j - - - org.slf4j - slf4j-api - - - org.slf4j - jul-to-slf4j - - - ch.qos.logback - logback-classic - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/logging/slf4j/src/main/java/io/helidon/examples/logging/slf4j/Main.java b/examples/logging/slf4j/src/main/java/io/helidon/examples/logging/slf4j/Main.java deleted file mode 100644 index 768e0d66d12..00000000000 --- a/examples/logging/slf4j/src/main/java/io/helidon/examples/logging/slf4j/Main.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.logging.slf4j; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - -import io.helidon.common.context.Context; -import io.helidon.common.context.Contexts; -import io.helidon.logging.common.HelidonMdc; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.http.HttpRouting; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.slf4j.MDC; - -/** - * Main class of the example, runnable from command line. - */ -public final class Main { - private static final Logger LOGGER = LoggerFactory.getLogger(Main.class); - private static final System.Logger SYSTEM_LOGGER = System.getLogger(Main.class.getName()); - - private Main() { - } - - /** - * Starts the example. - * - * @param args not used - */ - public static void main(String[] args) { - LogConfig.configureRuntime(); - - // the Helidon context is used to propagate MDC across threads - // if running within Helidon WebServer, you do not need to runInContext, as that is already - // done by the webserver - Contexts.runInContext(Context.create(), Main::logging); - - WebServer server = WebServer.builder() - .routing(Main::routing) - .build() - .start(); - } - - private static void routing(HttpRouting.Builder routing) { - routing.get("/", (req, res) -> { - HelidonMdc.set("name", String.valueOf(req.id())); - LOGGER.info("Running in webserver, id:"); - res.send("Hello"); - }); - } - - private static void logging() { - HelidonMdc.set("name", "startup"); - LOGGER.info("Starting up"); - SYSTEM_LOGGER.log(System.Logger.Level.INFO, "Using System logger"); - - // now let's see propagation across executor service boundary, we can also use Log4j's ThreadContext - MDC.put("name", "propagated"); - // wrap executor so it supports Helidon context, this is done for all built-in executors in Helidon - ExecutorService es = Contexts.wrap(Executors.newSingleThreadExecutor()); - - Future submit = es.submit(Main::log); - try { - submit.get(); - } catch (Exception e) { - e.printStackTrace(); - } - es.shutdown(); - } - - private static void log() { - LOGGER.info("Running on another thread"); - } -} diff --git a/examples/logging/slf4j/src/main/java/io/helidon/examples/logging/slf4j/package-info.java b/examples/logging/slf4j/src/main/java/io/helidon/examples/logging/slf4j/package-info.java deleted file mode 100644 index 3c108cf7c60..00000000000 --- a/examples/logging/slf4j/src/main/java/io/helidon/examples/logging/slf4j/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020 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. - */ - -/** - * Slf4j example with Mapped diagnostics context (MDC) in Helidon. - */ -package io.helidon.examples.logging.slf4j; diff --git a/examples/logging/slf4j/src/main/resources/logback.xml b/examples/logging/slf4j/src/main/resources/logback.xml deleted file mode 100644 index 7a6f59f85db..00000000000 --- a/examples/logging/slf4j/src/main/resources/logback.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - true - - - - - - %d{HH:mm:ss.SSS} %-5level [%thread] %logger{36} - %msg %X{name}%n - - - - - - - - \ No newline at end of file diff --git a/examples/logging/slf4j/src/main/resources/logging.properties b/examples/logging/slf4j/src/main/resources/logging.properties deleted file mode 100644 index 5e4967d7ca2..00000000000 --- a/examples/logging/slf4j/src/main/resources/logging.properties +++ /dev/null @@ -1,18 +0,0 @@ -# -# Copyright (c) 2024 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. -# - -# register SLF4JBridgeHandler as handler for the j.u.l. root logger -handlers=org.slf4j.bridge.SLF4JBridgeHandler diff --git a/examples/media/multipart/README.md b/examples/media/multipart/README.md deleted file mode 100644 index eb7ee218bf6..00000000000 --- a/examples/media/multipart/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Helidon SE MultiPart Example - -This example demonstrates how to use `MultiPartSupport` with both the `WebServer` - and `WebClient` APIs. - -This project implements a simple file service web application that supports uploading -and downloading files. The unit test uses the `WebClient` API to test the endpoints. - -## Build - -```shell -mvn package -``` - -## Run - -First, start the server: - -```shell -java -jar target/helidon-examples-media-multipart.jar -``` - -Then open in your browser. diff --git a/examples/media/multipart/pom.xml b/examples/media/multipart/pom.xml deleted file mode 100644 index cc2d47a85bf..00000000000 --- a/examples/media/multipart/pom.xml +++ /dev/null @@ -1,105 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.media - helidon-examples-media-multipart - Helidon Examples Media Support Multipart - - - Example of a form based file upload. - - - - io.helidon.examples.media.multipart.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.http.media - helidon-http-media-multipart - - - io.helidon.http.media - helidon-http-media-jsonp - - - io.helidon.webserver - helidon-webserver-static-content - - - jakarta.json - jakarta.json-api - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.apache.maven.plugins - maven-failsafe-plugin - - - - integration-test - verify - - - - - - - diff --git a/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/FileService.java b/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/FileService.java deleted file mode 100644 index 9000b19bd24..00000000000 --- a/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/FileService.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.media.multipart; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; -import java.util.Map; -import java.util.stream.Stream; - -import io.helidon.common.media.type.MediaTypes; -import io.helidon.http.ContentDisposition; -import io.helidon.http.Header; -import io.helidon.http.HeaderNames; -import io.helidon.http.HeaderValues; -import io.helidon.http.ServerResponseHeaders; -import io.helidon.http.media.multipart.MultiPart; -import io.helidon.http.media.multipart.ReadablePart; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -import jakarta.json.Json; -import jakarta.json.JsonArrayBuilder; -import jakarta.json.JsonBuilderFactory; - -import static io.helidon.http.Status.BAD_REQUEST_400; -import static io.helidon.http.Status.MOVED_PERMANENTLY_301; -import static io.helidon.http.Status.NOT_FOUND_404; - -/** - * File service. - */ -public final class FileService implements HttpService { - private static final Header UI_LOCATION = HeaderValues.createCached(HeaderNames.LOCATION, "/ui"); - private final JsonBuilderFactory jsonFactory; - private final Path storage; - - /** - * Create a new file upload service instance. - */ - FileService() { - jsonFactory = Json.createBuilderFactory(Map.of()); - storage = createStorage(); - System.out.println("Storage: " + storage); - } - - @Override - public void routing(HttpRules rules) { - rules.get("/", this::list) - .get("/{fname}", this::download) - .post("/", this::upload); - } - - private static Path createStorage() { - try { - return Files.createTempDirectory("fileupload"); - } catch (IOException ex) { - throw new RuntimeException(ex); - } - } - - private static Stream listFiles(Path storage) { - try (Stream walk = Files.walk(storage)) { - return walk.filter(Files::isRegularFile) - .map(storage::relativize) - .map(Path::toString) - .toList() - .stream(); - } catch (IOException ex) { - throw new RuntimeException(ex); - } - } - - private static OutputStream newOutputStream(Path storage, String fname) { - try { - return Files.newOutputStream(storage.resolve(fname), - StandardOpenOption.CREATE, - StandardOpenOption.WRITE, - StandardOpenOption.TRUNCATE_EXISTING); - } catch (IOException ex) { - throw new RuntimeException(ex); - } - } - - private void list(ServerRequest req, ServerResponse res) { - JsonArrayBuilder arrayBuilder = jsonFactory.createArrayBuilder(); - listFiles(storage).forEach(arrayBuilder::add); - res.send(jsonFactory.createObjectBuilder().add("files", arrayBuilder).build()); - } - - private void download(ServerRequest req, ServerResponse res) { - Path filePath = storage.resolve(req.path().pathParameters().get("fname")); - if (!filePath.getParent().equals(storage)) { - res.status(BAD_REQUEST_400).send("Invalid file name"); - return; - } - if (!Files.exists(filePath)) { - res.status(NOT_FOUND_404).send(); - return; - } - if (!Files.isRegularFile(filePath)) { - res.status(BAD_REQUEST_400).send("Not a file"); - return; - } - ServerResponseHeaders headers = res.headers(); - headers.contentType(MediaTypes.APPLICATION_OCTET_STREAM); - headers.set(ContentDisposition.builder() - .filename(filePath.getFileName().toString()) - .build()); - res.send(filePath); - } - - private void upload(ServerRequest req, ServerResponse res) { - MultiPart mp = req.content().as(MultiPart.class); - - while (mp.hasNext()) { - ReadablePart part = mp.next(); - if ("file[]".equals(URLDecoder.decode(part.name(), StandardCharsets.UTF_8))) { - try (InputStream in = part.inputStream(); OutputStream out = newOutputStream(storage, part.fileName().get())) { - in.transferTo(out); - } catch (IOException e) { - throw new RuntimeException("Failed to write content", e); - } - } - } - - res.status(MOVED_PERMANENTLY_301) - .header(UI_LOCATION) - .send(); - } -} diff --git a/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/Main.java b/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/Main.java deleted file mode 100644 index b961a934bc7..00000000000 --- a/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/Main.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.media.multipart; - -import io.helidon.http.Header; -import io.helidon.http.HeaderNames; -import io.helidon.http.HeaderValues; -import io.helidon.http.Status; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.staticcontent.StaticContentService; - -/** - * This application provides a simple file upload service with a UI to exercise multipart. - */ -public final class Main { - private static final Header UI_LOCATION = HeaderValues.createCached(HeaderNames.LOCATION, "/ui"); - - private Main() { - } - - /** - * Executes the example. - * - * @param args command line arguments, ignored - */ - public static void main(String[] args) { - WebServer server = WebServer.builder() - .routing(Main::routing) - .port(8080) - .build() - .start(); - - System.out.println("WEB server is up! http://localhost:" + server.port()); - } - - /** - * Updates the routing rules. - * - * @param rules routing rules - */ - static void routing(HttpRules rules) { - rules.any("/", (req, res) -> { - res.status(Status.MOVED_PERMANENTLY_301); - res.header(UI_LOCATION); - res.send(); - }) - .register("/ui", StaticContentService.builder("WEB") - .welcomeFileName("index.html") - .build()) - .register("/api", new FileService()); - } -} diff --git a/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/package-info.java b/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/package-info.java deleted file mode 100644 index 09e93541ec5..00000000000 --- a/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020, 2021 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. - */ - -/** - * Helidon Examples Media MultiPart. - */ -package io.helidon.examples.media.multipart; diff --git a/examples/media/multipart/src/main/resources/WEB/index.html b/examples/media/multipart/src/main/resources/WEB/index.html deleted file mode 100644 index cc055977e07..00000000000 --- a/examples/media/multipart/src/main/resources/WEB/index.html +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - Helidon Examples Media Multipart - - - - - -

      Uploaded files

      -
      - -

      Upload (buffered)

      -
      - Select a file to upload: - - -
      - -

      Upload (stream)

      -
      - Select a file to upload: - - -
      - - - - diff --git a/examples/media/multipart/src/main/resources/logging.properties b/examples/media/multipart/src/main/resources/logging.properties deleted file mode 100644 index 8e43cf46e7e..00000000000 --- a/examples/media/multipart/src/main/resources/logging.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# Copyright (c) 2018, 2023 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. -# - -handlers=java.util.logging.ConsoleHandler -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS.%1$tL %5$s%6$s%n -# Global logging level. Can be overridden by specific loggers -.level=INFO -io.helidon.webserver.level=INFO diff --git a/examples/media/multipart/src/test/java/io/helidon/examples/media/multipart/FileServiceTest.java b/examples/media/multipart/src/test/java/io/helidon/examples/media/multipart/FileServiceTest.java deleted file mode 100644 index 52685cf9a6a..00000000000 --- a/examples/media/multipart/src/test/java/io/helidon/examples/media/multipart/FileServiceTest.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.media.multipart; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; - -import io.helidon.common.media.type.MediaTypes; -import io.helidon.http.HeaderNames; -import io.helidon.http.Status; -import io.helidon.http.media.multipart.WriteableMultiPart; -import io.helidon.http.media.multipart.WriteablePart; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.http.HttpRouting; -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpRoute; - -import jakarta.json.JsonObject; -import jakarta.json.JsonString; -import org.hamcrest.Matchers; -import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.Matchers.notNullValue; - -/** - * Tests {@link FileService}. - */ -@TestMethodOrder(OrderAnnotation.class) -@ServerTest -public class FileServiceTest { - private final Http1Client client; - - FileServiceTest(Http1Client client) { - this.client = client; - } - - @SetUpRoute - static void routing(HttpRouting.Builder builder) { - Main.routing(builder); - } - - @Test - @Order(1) - public void testUpload() throws IOException { - Path file = Files.writeString(Files.createTempFile(null, null), "bar\n"); - try (Http1ClientResponse response = client.post("/api") - .followRedirects(false) - .submit(WriteableMultiPart.builder() - .addPart(writeablePart("file[]", "foo.txt", file)) - .build())) { - assertThat(response.status(), is(Status.MOVED_PERMANENTLY_301)); - } - } - - @Test - @Order(2) - public void testStreamUpload() throws IOException { - Path file = Files.writeString(Files.createTempFile(null, null), "stream bar\n"); - Path file2 = Files.writeString(Files.createTempFile(null, null), "stream foo\n"); - try (Http1ClientResponse response = client.post("/api") - .queryParam("stream", "true") - .followRedirects(false) - .submit(WriteableMultiPart - .builder() - .addPart(writeablePart("file[]", "streamed-foo.txt", file)) - .addPart(writeablePart("otherPart", "streamed-foo2.txt", file2)) - .build())) { - assertThat(response.status(), is(Status.MOVED_PERMANENTLY_301)); - } - } - - @Test - @Order(3) - public void testList() { - try (Http1ClientResponse response = client.get("/api").request()) { - assertThat(response.status(), is(Status.OK_200)); - JsonObject json = response.as(JsonObject.class); - assertThat(json, Matchers.is(notNullValue())); - List files = json.getJsonArray("files").getValuesAs(v -> ((JsonString) v).getString()); - assertThat(files, hasItem("foo.txt")); - } - } - - @Test - @Order(4) - public void testDownload() { - try (Http1ClientResponse response = client.get("/api").path("foo.txt").request()) { - assertThat(response.status(), is(Status.OK_200)); - assertThat(response.headers().first(HeaderNames.CONTENT_DISPOSITION).orElse(null), - containsString("filename=\"foo.txt\"")); - byte[] bytes = response.as(byte[].class); - assertThat(new String(bytes, StandardCharsets.UTF_8), Matchers.is("bar\n")); - } - } - - private WriteablePart writeablePart(String partName, String fileName, Path filePath) throws IOException { - return WriteablePart.builder(partName) - .fileName(fileName) - .content(Files.readAllBytes(filePath)) - .contentType(MediaTypes.MULTIPART_FORM_DATA) - .build(); - } -} diff --git a/examples/media/pom.xml b/examples/media/pom.xml deleted file mode 100644 index 544752e31e8..00000000000 --- a/examples/media/pom.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples - helidon-examples-project - 4.1.0-SNAPSHOT - - io.helidon.examples.media - helidon-examples-media-project - Helidon Examples Media Support - pom - - - Examples of Helidon Media usage - - - - multipart - - diff --git a/examples/messaging/README.md b/examples/messaging/README.md deleted file mode 100644 index 63201c10fb3..00000000000 --- a/examples/messaging/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# Helidon Messaging Examples - -## Prerequisites -* Docker -* Java 21+ - -### Test Kafka server -To make examples easily runnable, -small, pocket size and pre-configured testing Kafka server Docker image is available. - -* To run it locally: `./kafkaRun.sh` - * Pre-configured topics: - * `messaging-test-topic-1` - * `messaging-test-topic-2` - * Stop it with `Ctrl+c` - -* Send messages manually with: `./kafkaProduce.sh [topic-name]` -* Consume messages manually with: `./kafkaConsume.sh [topic-name]` - -### Test JMS server -* Start ActiveMQ server locally: -```shell -docker run --name='activemq' --rm -p 61616:61616 -p 8161:8161 rmohr/activemq -``` - -### Test Oracle database -* Start ActiveMQ server locally: -```shell -cd ./docker/oracle-aq-18-xe -./buildAndRun.sh -``` - -For stopping Oracle database container use: -```shell -cd ./docker/oracle-aq-18-xe -./stopAndClean.sh -``` - -## Helidon SE Reactive Messaging with Kafka Example -For demonstration of Helidon SE Messaging with Kafka connector, -continue to [Kafka with WebSocket SE Example](kafka-websocket-se/README.md) - -## Helidon MP Reactive Messaging with Kafka Example -For demonstration of Helidon MP Messaging with Kafka connector, -continue to [Kafka with WebSocket MP Example](kafka-websocket-mp/README.md) - -## Helidon MP Reactive Messaging with JMS Example -For demonstration of Helidon MP Messaging with JMS connector, -continue to [JMS with WebSocket MP Example](jms-websocket-mp/README.md) - -## Helidon MP Reactive Messaging with Oracle AQ Example -For demonstration of Helidon MP Messaging with Oracle Advance Queueing connector, -continue to [Oracle AQ with WebSocket MP Example](oracle-aq-websocket-mp/README.md) - - diff --git a/examples/messaging/docker/kafka/Dockerfile.kafka b/examples/messaging/docker/kafka/Dockerfile.kafka deleted file mode 100644 index 761977c96ed..00000000000 --- a/examples/messaging/docker/kafka/Dockerfile.kafka +++ /dev/null @@ -1,51 +0,0 @@ -# -# Copyright (c) 2019, 2024 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. -# - -FROM container-registry.oracle.com/java/jdk-no-fee-term:21 - -ENV VERSION=2.7.0 -ENV SCALA_VERSION=2.13 - -RUN dnf update && dnf -y install wget jq nc - -RUN REL_PATH=kafka/${VERSION}/kafka_${SCALA_VERSION}-${VERSION}.tgz \ -&& BACKUP_ARCHIVE=https://archive.apache.org/dist/ \ -&& echo "Looking for closest mirror ..." \ -&& MIRROR=$(curl -s 'https://www.apache.org/dyn/closer.cgi?as_json=1' | jq -r '.http[0]') \ -&& echo "Checking if version ${VERSION} is available on the mirror: ${MIRROR} ..." \ -&& MIRROR_RESPONSE=$(curl -L --write-out '%{http_code}' --silent --output /dev/null ${MIRROR}kafka/${VERSION}) \ -&& if [ $MIRROR_RESPONSE -eq 200 ]; then BIN_URL=${MIRROR}${REL_PATH}; else BIN_URL=${BACKUP_ARCHIVE}${REL_PATH}; fi \ -&& if [ $MIRROR_RESPONSE -ne 200 ]; then echo "Version ${VERSION} not found on the mirror ${MIRROR}, defaulting to archive ${BACKUP_ARCHIVE}."; fi \ -&& wget -q -O kafka.tar.gz ${BIN_URL} \ -&& tar -xzf kafka.tar.gz -C /opt && rm kafka.tar.gz \ -&& mv /opt/kafka* /opt/kafka - -WORKDIR /opt/kafka - -COPY start_kafka.sh start_kafka.sh -COPY init_topics.sh init_topics.sh - -RUN chmod a+x ./*.sh - -RUN echo listener.security.protocol.map=INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT >> config/server.properties \ -&& echo advertised.listeners=INSIDE://localhost:9092,OUTSIDE://localhost:29092 >> config/server.properties \ -&& echo listeners=INSIDE://0.0.0.0:9092,OUTSIDE://0.0.0.0:29092 >> config/server.properties \ -&& echo inter.broker.listener.name=INSIDE >> config/server.properties - -# Expose Zookeeper and Kafka ports -EXPOSE 2181 9092 29092 - -CMD bash start_kafka.sh diff --git a/examples/messaging/docker/kafka/init_topics.sh b/examples/messaging/docker/kafka/init_topics.sh deleted file mode 100644 index 90864ce5fb5..00000000000 --- a/examples/messaging/docker/kafka/init_topics.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2020, 2024 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. -# - -# -# Wait for Kafka to start and create test topics: -# topic messaging-test-topic-1 and topic messaging-test-topic-2 -# - -ZOOKEEPER_URL=localhost:2181 -KAFKA_TOPICS="/opt/kafka/bin/kafka-topics.sh --if-not-exists --zookeeper ${ZOOKEEPER_URL}" - -while sleep 2; do - brokers=$(echo dump | nc localhost 2181 | grep -c brokers) - echo "Checking if Kafka is up: ${brokers}" - if [[ "$brokers" -gt "0" ]]; then - echo "KAFKA IS UP !!!" - - echo "Creating test topics" - bash "${KAFKA_TOPICS}" \ - --create \ - --replication-factor 1 \ - --partitions 10 \ - --topic messaging-test-topic-1 - bash "${KAFKA_TOPICS}" \ - --create \ - --replication-factor 1 \ - --partitions 10 \ - --topic messaging-test-topic-2 - bash "${KAFKA_TOPICS}" \ - --create \ - --replication-factor 1 \ - --partitions 10 \ - --config compression.type=snappy \ - --topic messaging-test-topic-snappy-compressed - bash "${KAFKA_TOPICS}" \ - --create \ - --replication-factor 1 \ - --partitions 10 \ - --config compression.type=lz4 \ - --topic messaging-test-topic-lz4-compressed - bash "${KAFKA_TOPICS}" \ - --create \ - --replication-factor 1 \ - --partitions 10 \ - --config compression.type=zstd \ - --topic messaging-test-topic-zstd-compressed - bash "${KAFKA_TOPICS}" \ - --create \ - --replication-factor 1 \ - --partitions 10 \ - --config compression.type=gzip \ - --topic messaging-test-topic-gzip-compressed - - echo - echo "Example topics created:" - echo " messaging-test-topic-1" - echo " messaging-test-topic-2" - echo " messaging-test-topic-snappy-compressed" - echo " messaging-test-topic-lz4-compressed" - echo " messaging-test-topic-zstd-compressed" - echo " messaging-test-topic-gzip-compressed" - echo - echo "================== Kafka is ready, stop it with Ctrl+C ==================" - exit 0 - fi -done diff --git a/examples/messaging/docker/kafka/start_kafka.sh b/examples/messaging/docker/kafka/start_kafka.sh deleted file mode 100644 index 0bf0323acd1..00000000000 --- a/examples/messaging/docker/kafka/start_kafka.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2020, 2024 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. -# - -# -# Start Zookeeper, wait for it to come up and start Kafka. -# - -# Allow ruok -echo "4lw.commands.whitelist=*" >>/opt/kafka/config/zookeeper.properties - -# Start Zookeeper -/opt/kafka/bin/zookeeper-server-start.sh /opt/kafka/config/zookeeper.properties & - -while sleep 2; do - isOk=$(echo ruok | nc localhost 2181) - echo "Checking if Zookeeper is up: ${isOk}" - if [ "${isOk}" = "imok" ]; then - echo "ZOOKEEPER IS UP !!!" - break - fi -done - -# Create test topics when Kafka is ready -/opt/kafka/init_topics.sh & - -# Start Kafka -/opt/kafka/bin/kafka-server-start.sh /opt/kafka/config/server.properties -state=$? -if [ $state -ne 0 ]; then - echo "Kafka stopped." - exit $state -fi - -# Keep Kafka up till Ctrl+C -read -r ; diff --git a/examples/messaging/docker/oracle-aq-18-xe/Dockerfile b/examples/messaging/docker/oracle-aq-18-xe/Dockerfile deleted file mode 100644 index 7232e775f6e..00000000000 --- a/examples/messaging/docker/oracle-aq-18-xe/Dockerfile +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2020 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. -# - -FROM oracle/database:18.4.0-xe as base - - -COPY init.sql /docker-entrypoint-initdb.d/setup/ \ No newline at end of file diff --git a/examples/messaging/docker/oracle-aq-18-xe/buildAndRun.sh b/examples/messaging/docker/oracle-aq-18-xe/buildAndRun.sh deleted file mode 100755 index 6c0095563e1..00000000000 --- a/examples/messaging/docker/oracle-aq-18-xe/buildAndRun.sh +++ /dev/null @@ -1,102 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2020, 2024 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. -# - -CURR_DIR=$(pwd) -TEMP_DIR=../../target -IMAGES_DIR=${TEMP_DIR}/ora-images -COMMIT="a69fe9b08ff147bb746d16af76cc5279ea5baf7a"; -IMAGES_ZIP_URL=https://github.com/oracle/docker-images/archive/${COMMIT:0:7}.zip -IMAGES_ZIP_DIR=docker-images-${COMMIT}/OracleDatabase/SingleInstance/dockerfiles -ORA_DB_VERSION=18.4.0 -BASE_IMAGE_NAME=oracle/database:${ORA_DB_VERSION}-xe -IMAGE_NAME=helidon/oracle-aq-example -CONTAINER_NAME=oracle-aq-example -ORACLE_PWD=frank - -printf "%-100s" "Checking if base image ${BASE_IMAGE_NAME} is available in local repository" -if [[ "$(docker images -q ${BASE_IMAGE_NAME} 2>/dev/null)" == "" ]]; then - printf "NOK\n" - - echo Base image ${BASE_IMAGE_NAME} not found. Building ... - - # cleanup - mkdir -p ${TEMP_DIR} - rm -rf ${IMAGES_DIR} - rm -f ${TEMP_DIR}/ora-images.zip - - # download official oracle docker images - curl -LJ -o ${TEMP_DIR}/ora-images.zip "${IMAGES_ZIP_URL}" - # unzip only image for Oracle database 18.4.0 - unzip -qq ${TEMP_DIR}/ora-images.zip "${IMAGES_ZIP_DIR}/*" -d ${IMAGES_DIR} - mv ${IMAGES_DIR}/${IMAGES_ZIP_DIR}/${ORA_DB_VERSION} ${IMAGES_DIR}/ - mv ${IMAGES_DIR}/${IMAGES_ZIP_DIR}/buildContainerImage.sh ${IMAGES_DIR}/ - - # cleanup - rm -rf ${IMAGES_DIR}/docker-images-${COMMIT} - rm ${TEMP_DIR}/ora-images.zip - - # build base image - # can take long(15 minutes or so) - cd ${IMAGES_DIR} || exit - bash ./buildContainerImage.sh -v ${ORA_DB_VERSION} -x || exit - cd "${CURR_DIR}" || exit -else - printf "OK\n" -fi - -printf "%-100s" "Checking if image ${IMAGE_NAME} is available in local repository" -if [[ "$(docker images -q ${IMAGE_NAME} 2>/dev/null)" == "" ]]; then - printf "NOK\n" - - echo Image ${IMAGE_NAME} not found. Building ... - docker build -t ${IMAGE_NAME} . || exit -else - printf "OK\n" -fi - -printf "%-100s" "Checking if container ${CONTAINER_NAME} is ready" -if [[ $(docker ps -a --filter "name=^/${CONTAINER_NAME}$" --format '{{.Names}}') != "${CONTAINER_NAME}" ]]; then - printf "NOK\n" - - echo "Container ${CONTAINER_NAME} not found. Running ..." - echo "!!! Be aware first time database initialization can take tens of minutes." - echo "!!! Follow docker logs -f ${CONTAINER_NAME} for 'DATABASE IS READY TO USE' message" - - docker run -d --name ${CONTAINER_NAME} \ - -p 1521:1521 \ - -p 5500:5500 \ - -e ORACLE_PWD=${ORACLE_PWD} \ - ${IMAGE_NAME} || exit -else - printf "OK\n" - printf "%-100s" "Checking if container ${CONTAINER_NAME} is started" - if [[ $(docker ps --filter "name=^/${CONTAINER_NAME}$" --format '{{.Names}}') != "${CONTAINER_NAME}" ]]; then - printf "NOK\n" - - echo "Container ${CONTAINER_NAME} not started. Starting ..." - docker start ${CONTAINER_NAME} || exit - else - printf "OK\n" - fi -fi - -echo "Container ${CONTAINER_NAME} with Oracle database ${ORA_DB_VERSION} XE populated with example AQ queues is either started or starting." -echo "For more info about the state of the database investigate logs:" -echo " docker logs -f ${CONTAINER_NAME}" -echo "Url: jdbc:oracle:thin:@localhost:1521:XE" -echo "user: frank" -echo "pass: frank" diff --git a/examples/messaging/docker/oracle-aq-18-xe/examples.sql b/examples/messaging/docker/oracle-aq-18-xe/examples.sql deleted file mode 100644 index 9a89352ba19..00000000000 --- a/examples/messaging/docker/oracle-aq-18-xe/examples.sql +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2020 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. - */ - - --- SEND MESSAGE AS RAW BYTES -DECLARE - id pls_integer; - enqueue_options DBMS_AQ.ENQUEUE_OPTIONS_T; - message_properties DBMS_AQ.MESSAGE_PROPERTIES_T; - message_handle RAW(16); - msg sys.aq$_jms_bytes_message; -BEGIN - msg := sys.aq$_jms_bytes_message.construct; - id := msg.clear_body(-1); - msg.write_bytes(id, UTL_RAW.CAST_TO_RAW('Hello raw bytes!')); - msg.flush(id); - DBMS_AQ.ENQUEUE( - queue_name => 'FRANK.EXAMPLE_QUEUE_BYTES', - enqueue_options => enqueue_options, - message_properties => message_properties, - payload => msg, - msgid => message_handle); - COMMIT; -END; - --- SEND TEXT MESSAGE -DECLARE - enqueue_options DBMS_AQ.ENQUEUE_OPTIONS_T; - message_properties DBMS_AQ.MESSAGE_PROPERTIES_T; - message_handle RAW(16); - msg SYS.AQ$_JMS_TEXT_MESSAGE; -BEGIN - msg := SYS.AQ$_JMS_TEXT_MESSAGE.construct; - msg.set_text('Hello from PLSQL !'); - DBMS_AQ.ENQUEUE( - queue_name => 'FRANK.EXAMPLE_QUEUE_1', - enqueue_options => enqueue_options, - message_properties => message_properties, - payload => msg, - msgid => message_handle); - COMMIT; -END; - --- SEND MAP MESSAGE -DECLARE - id pls_integer; - enqueue_options DBMS_AQ.ENQUEUE_OPTIONS_T; - message_properties DBMS_AQ.MESSAGE_PROPERTIES_T; - message_handle RAW(16); - msg SYS.AQ$_JMS_MAP_MESSAGE; -BEGIN - msg := SYS.AQ$_JMS_MAP_MESSAGE.construct; - id := msg.clear_body(-1); - msg.set_string(id, 'head', 'Hello'); - msg.set_bytes(id, 'body', UTL_RAW.CAST_TO_RAW('this is map')); - msg.set_string(id, 'tail', 'message!'); - msg.flush(id); - DBMS_AQ.ENQUEUE( - queue_name => 'FRANK.EXAMPLE_QUEUE_MAP', - enqueue_options => enqueue_options, - message_properties => message_properties, - payload => msg, - msgid => message_handle); - COMMIT; -END; \ No newline at end of file diff --git a/examples/messaging/docker/oracle-aq-18-xe/init.sql b/examples/messaging/docker/oracle-aq-18-xe/init.sql deleted file mode 100644 index 01d6300aa04..00000000000 --- a/examples/messaging/docker/oracle-aq-18-xe/init.sql +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2020 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. - */ - - -alter session set "_ORACLE_SCRIPT"= true; -create user frank identified by frank; -grant dba to frank; - -grant execute on dbms_aq to frank; -grant execute on dbms_aqadm to frank; -grant execute on dbms_aqin to frank; - -CREATE OR REPLACE PROCEDURE create_queue(queueName IN VARCHAR2, qType IN VARCHAR2) IS -BEGIN - dbms_aqadm.create_queue_table('FRANK.'||queueName||'_TAB', qType); - dbms_aqadm.create_queue('FRANK.'||queueName,'FRANK.'||queueName||'_TAB'); - dbms_aqadm.start_queue('FRANK.'||queueName); -END; -/ - --- Setup example AQ queues FRANK.EXAMPLE_QUEUE_1, FRANK.EXAMPLE_QUEUE_2, FRANK.EXAMPLE_QUEUE_3 -begin - CREATE_QUEUE('example_queue_1', 'SYS.AQ$_JMS_TEXT_MESSAGE'); - CREATE_QUEUE('example_queue_2', 'SYS.AQ$_JMS_TEXT_MESSAGE'); - CREATE_QUEUE('example_queue_3', 'SYS.AQ$_JMS_TEXT_MESSAGE'); - CREATE_QUEUE('example_queue_bytes', 'SYS.AQ$_JMS_BYTES_MESSAGE'); - CREATE_QUEUE('example_queue_map', 'SYS.AQ$_JMS_MAP_MESSAGE'); -end; -/ - --- Setup example table -CREATE TABLE FRANK.MESSAGE_LOG ( - id NUMBER(15) PRIMARY KEY, - message VARCHAR2(255) NOT NULL, - insert_date DATE DEFAULT (sysdate)); -COMMENT ON TABLE FRANK.MESSAGE_LOG IS 'Manually logged messages'; - -CREATE SEQUENCE FRANK.MSG_LOG_SEQ START WITH 1; - -CREATE OR REPLACE TRIGGER MESSAGE_LOG_ID - BEFORE INSERT ON FRANK.MESSAGE_LOG - FOR EACH ROW - -BEGIN - SELECT FRANK.MSG_LOG_SEQ.NEXTVAL - INTO :new.id - FROM dual; -END; -/ diff --git a/examples/messaging/docker/oracle-aq-18-xe/stopAndClean.sh b/examples/messaging/docker/oracle-aq-18-xe/stopAndClean.sh deleted file mode 100755 index 4ba52254147..00000000000 --- a/examples/messaging/docker/oracle-aq-18-xe/stopAndClean.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2020, 2024 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. -# - -docker stop oracle-aq-example -docker container rm oracle-aq-example -docker image rm helidon/oracle-aq-example:latest \ No newline at end of file diff --git a/examples/messaging/jms-websocket-mp/README.md b/examples/messaging/jms-websocket-mp/README.md deleted file mode 100644 index bb3aeaa9e34..00000000000 --- a/examples/messaging/jms-websocket-mp/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Helidon Messaging with JMS Example - -## Prerequisites -* Java 21+ -* Docker -* [ActiveMQ server](../README.md) running on `localhost:61616` - -## Build & Run -```shell -#1. -mvn clean package -#2. - java -jar target/helidon-examples-jms-websocket-mp.jar -``` -3. Visit http://localhost:7001 - diff --git a/examples/messaging/jms-websocket-mp/pom.xml b/examples/messaging/jms-websocket-mp/pom.xml deleted file mode 100644 index f5154e052db..00000000000 --- a/examples/messaging/jms-websocket-mp/pom.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.jms - helidon-examples-jms-websocket-mp - 1.0-SNAPSHOT - Helidon Examples Messaging JMS WebSocket SE - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.microprofile.messaging - helidon-microprofile-messaging - - - io.helidon.messaging.jms - helidon-messaging-jms - - - io.helidon.microprofile.websocket - helidon-microprofile-websocket - - - io.smallrye - jandex - runtime - true - - - org.apache.activemq - activemq-client - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/messaging/jms-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/MsgProcessingBean.java b/examples/messaging/jms-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/MsgProcessingBean.java deleted file mode 100644 index 2b2e64c3d94..00000000000 --- a/examples/messaging/jms-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/MsgProcessingBean.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.messaging.mp; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.SubmissionPublisher; - -import io.helidon.common.reactive.Multi; -import io.helidon.messaging.connectors.jms.JmsMessage; - -import jakarta.enterprise.context.ApplicationScoped; -import org.eclipse.microprofile.reactive.messaging.Incoming; -import org.eclipse.microprofile.reactive.messaging.Message; -import org.eclipse.microprofile.reactive.messaging.Outgoing; -import org.eclipse.microprofile.reactive.streams.operators.ProcessorBuilder; -import org.eclipse.microprofile.reactive.streams.operators.ReactiveStreams; -import org.reactivestreams.FlowAdapters; -import org.reactivestreams.Publisher; - -/** - * Bean for message processing. - */ -@ApplicationScoped -public class MsgProcessingBean { - - private final SubmissionPublisher emitter = new SubmissionPublisher<>(); - private final SubmissionPublisher broadCaster = new SubmissionPublisher<>(); - - /** - * Create a publisher for the emitter. - * - * @return A Publisher from the emitter - */ - @Outgoing("multiplyVariants") - public Publisher preparePublisher() { - // Create new publisher for emitting to by this::process - return ReactiveStreams - .fromPublisher(FlowAdapters.toPublisher(Multi.create(emitter))) - .buildRs(); - } - - /** - * Returns a builder for a processor that maps a string into three variants. - * - * @return ProcessorBuilder - */ - @Incoming("multiplyVariants") - @Outgoing("toJms") - public ProcessorBuilder> multiply() { - // Multiply to 3 variants of same message - return ReactiveStreams.builder() - .flatMap(o -> - ReactiveStreams.of( - // upper case variant - o.toUpperCase(), - // repeat twice variant - o.repeat(2), - // reverse chars 'tnairav' - new StringBuilder(o).reverse().toString()) - ).map(Message::of); - } - - /** - * Broadcasts an event. - * - * @param msg Message to broadcast - * @return completed stage - */ - @Incoming("fromJms") - public CompletionStage broadcast(JmsMessage msg) { - // Broadcast to all subscribers - broadCaster.submit(msg.getPayload()); - return CompletableFuture.completedFuture(null); - } - - /** - * Same JMS session, different connector. - * - * @param msg Message to broadcast - * @return completed stage - */ - @Incoming("fromJmsSameSession") - public CompletionStage sameSession(JmsMessage msg) { - // Broadcast to all subscribers - broadCaster.submit(msg.getPayload()); - return CompletableFuture.completedFuture(null); - } - - /** - * Subscribe new Multi to broadcasting publisher. - * - * @return new Multi subscribed to broadcaster - */ - public Multi subscribeMulti() { - return Multi.create(broadCaster); - } - - /** - * Emit a message. - * - * @param msg message to emit - */ - public void process(final String msg) { - emitter.submit(msg); - } -} diff --git a/examples/messaging/jms-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/SendingResource.java b/examples/messaging/jms-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/SendingResource.java deleted file mode 100644 index 7000c579aeb..00000000000 --- a/examples/messaging/jms-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/SendingResource.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2020, 2021 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.messaging.mp; - -import jakarta.enterprise.context.RequestScoped; -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; - -/** - * Expose send method for publishing to messaging. - */ -@Path("rest/messages") -@RequestScoped -public class SendingResource { - private final MsgProcessingBean msgBean; - - /** - * Constructor injection of field values. - * - * @param msgBean Messaging example bean - */ - @Inject - public SendingResource(MsgProcessingBean msgBean) { - this.msgBean = msgBean; - } - - /** - * Send message through Messaging to JMS. - * - * @param msg message to process - */ - @Path("/send/{msg}") - @GET - @Produces(MediaType.APPLICATION_JSON) - public void getSend(@PathParam("msg") String msg) { - msgBean.process(msg); - } -} diff --git a/examples/messaging/jms-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/WebSocketEndpoint.java b/examples/messaging/jms-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/WebSocketEndpoint.java deleted file mode 100644 index 757f450b5f6..00000000000 --- a/examples/messaging/jms-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/WebSocketEndpoint.java +++ /dev/null @@ -1,95 +0,0 @@ - -/* - * Copyright (c) 2020, 2021 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.messaging.mp; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.helidon.common.reactive.Single; - -import jakarta.inject.Inject; -import jakarta.websocket.CloseReason; -import jakarta.websocket.EndpointConfig; -import jakarta.websocket.OnClose; -import jakarta.websocket.OnOpen; -import jakarta.websocket.Session; -import jakarta.websocket.server.ServerEndpoint; - -/** - * Register all WebSocket connection as subscribers - * of broadcasting {@link java.util.concurrent.SubmissionPublisher} - * in the {@link MsgProcessingBean}. - *

      - * When connection is closed, cancel subscription and remove reference. - */ -@ServerEndpoint("/ws/messages") -public class WebSocketEndpoint { - - private static final Logger LOGGER = Logger.getLogger(WebSocketEndpoint.class.getName()); - - private final Map> subscriberRegister = new HashMap<>(); - - @Inject - private MsgProcessingBean msgProcessingBean; - - /** - * On WebSocket session is opened. - * - * @param session web socket session - * @param endpointConfig endpoint config - */ - @OnOpen - public void onOpen(Session session, EndpointConfig endpointConfig) { - System.out.println("New WebSocket client connected with session " + session.getId()); - - Single single = msgProcessingBean.subscribeMulti() - // Watch for errors coming from upstream - .onError(throwable -> LOGGER.log(Level.SEVERE, "Upstream error!", throwable)) - // Send every item coming from upstream over web socket - .forEach(s -> sendTextMessage(session, s)); - - //Save forEach single promise for later cancellation - subscriberRegister.put(session.getId(), single); - } - - /** - * When WebSocket session is closed. - * - * @param session web socket session - * @param closeReason web socket close reason - */ - @OnClose - public void onClose(final Session session, final CloseReason closeReason) { - LOGGER.info("Closing session " + session.getId()); - // Properly unsubscribe from SubmissionPublisher - Optional.ofNullable(subscriberRegister.remove(session.getId())) - .ifPresent(Single::cancel); - } - - private void sendTextMessage(Session session, String msg) { - try { - session.getBasicRemote().sendText(msg); - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Message sending over WebSocket failed", e); - } - } -} diff --git a/examples/messaging/jms-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/package-info.java b/examples/messaging/jms-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/package-info.java deleted file mode 100644 index 75a27ea50bc..00000000000 --- a/examples/messaging/jms-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ - -/* - * Copyright (c) 2020, 2021 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. - */ - -/** - * Reactive Messaging JMS example. - */ -package io.helidon.examples.messaging.mp; diff --git a/examples/messaging/jms-websocket-mp/src/main/resources/META-INF/beans.xml b/examples/messaging/jms-websocket-mp/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 4a5ec955fb7..00000000000 --- a/examples/messaging/jms-websocket-mp/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/messaging/jms-websocket-mp/src/main/resources/WEB/favicon.ico b/examples/messaging/jms-websocket-mp/src/main/resources/WEB/favicon.ico deleted file mode 100644 index d91659fdb53c934af789e9b93e2d92c679f975d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1230 zcmV;<1Tp)GP)*8l(j8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H11WQRoK~z|Uy_Z{T6lE00e`jX8mqMWtT1?w51zW;RQDQ<{=()Hdzz zw!1sW2fMg*x83dr`hWW7ob&&FCuhEyofXfTJ#V90OB%YTYYw|#iqKDJj0GMwK@Y%Lzb*2G_bGtSTx(vr7!0A-X zHY!8QihhFz^yc-LWJMPj_pR+MShshrgzV#hCzVZx^mxsF+CGF=0g7G^6xo&($5mbY zRU=mL$Bvzg{1cN{v^qesy}_f-QEV5Pufbps^#z|0E2J zJyz}e*Pm0dHv$96aq&}Dc-QIF?TMP7ook+Zwz{~M`igKuIKUO}#-k`(0XumEaWYG1 zxfWQ4oQVxi%aZoGC63%h^D_sdv4n5{-+}5+6kbjPjv=^9XFKynxC}7K!Hw-JUA7_Q z+)_8%CRg@Xzp3!vh!A7s!|gQXuF?{h>9p{@R_W@r42p)=SP6W$Hc<9MUBQV5@k8F-Od+!DwicL++HXZpB zC>zZl3`18KfDYSW!={DO8_kV6_NXo&tq5jB2G*gRNnRbVz7S`AxlUu1Z1memKcl6e@BcFUqZIhcm4*geIb?&ONqhXK8GBAj}^Zx{0VTbCj)n4Q0uQ@WOY3GbL<) z4%~OMZLl?FTJv)B(5m^FE27uGo$Wf+`qR~JkfcvhC=~8aSTtitV5uFpcLBN4SYEbu za$=_8ztA~&bCdx!9ntmCFVD8LwzMq*%w*sp*>U&0XotVnRy}M8lMAL;Cjh;-Fyq)9 zPsW1|6E#io=VeCs3=S+l1BWlMtO?K|y>C7OHf>NCK>gxNa_|4+r0 z&65W0&@qMkW5V{hzyUlfzsOTVTLhUNh2P<^|1aOc>Q2L8Ezli}jT;=Gecy(kQ8oa< safbu=4pe_F$QIK3H*|aCS+%?NUyMb7$(BA=Gynhq07*qoM6N<$f|!R&8~^|S diff --git a/examples/messaging/jms-websocket-mp/src/main/resources/WEB/img/arrow-1.png b/examples/messaging/jms-websocket-mp/src/main/resources/WEB/img/arrow-1.png deleted file mode 100644 index bbba0aef8a6ce9efc80b64f1820f5eb38d83a209..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18222 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 L($S*M>{`;laxc~L diff --git a/examples/messaging/jms-websocket-mp/src/main/resources/WEB/img/frank.png b/examples/messaging/jms-websocket-mp/src/main/resources/WEB/img/frank.png deleted file mode 100644 index 51a13d8db8bc02ad1613da3b809cff394462a77a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10516 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 - - - - - - - Helidon Reactive Messaging - - - - - - - - -

      -
      -
      - -
      -
      Send
      -
      -
      -
      -
      -
      REST call /rest/messages/send/{msg}
      -
      -
      -
      Messages received from JMS over websocket
      -
      -
      -
      -
      -
      -            
      -        
      -
      -
      - - - - - \ No newline at end of file diff --git a/examples/messaging/jms-websocket-mp/src/main/resources/WEB/main.css b/examples/messaging/jms-websocket-mp/src/main/resources/WEB/main.css deleted file mode 100644 index 358c7857297..00000000000 --- a/examples/messaging/jms-websocket-mp/src/main/resources/WEB/main.css +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2020, 2021 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. - */ - -#root { - background-color: #36ABF2; - font-family: Roboto,sans-serif; - color: #fff; - position: absolute; - overflow-x: hidden; - -ms-overflow-style: none; /* Internet Explorer 10+ */ - scrollbar-width: none; /* Firefox */ - top: 0; - left: 0; - width: 100%; - height: 100%; -} -#root::-webkit-scrollbar { - display: none; /* Safari and Chrome */ -} - -#helidon { - width: 509px; - height: 273px; - position: relative; - left: -509px; - z-index: 4; - background: url('img/frank.png'); -} - -#rest-tip { - position: relative; - top: -80px; - left: 160px; -} - -#rest-tip-arrow { - width: 205px; - height: 304px; - z-index: 4; - top: -20px; - background: url('img/arrow-1.png'); -} -#rest-tip-label { - position: absolute; - white-space: nowrap; - font-size: 18px; - font-weight: bold; - z-index: 4; - left: -60px; -} - -#sse-tip { - position: absolute; - overflow: hidden; - display: flex; - width: auto; - height: auto; - top: 5%; - right: 10%; - z-index: 0; -} - -#sse-tip-arrow { - position: relative; - top: -30px; - width: 296px; - height: 262px; - z-index: 4; - background: url('img/arrow-2.png'); -} -#sse-tip-label { - position: relative; - white-space: nowrap; - font-size: 18px; - font-weight: bold; - z-index: 4; -} - -#producer { - float: left; - position: relative; - width: 300px; - height: 100%; - margin: 50px; - padding: 10px; - z-index: 99; -} - -#msgBox { - position: absolute; - width: 300px; - top: 25%; - right: 3%; - height: 100%; - margin: 50px; - padding: 10px; - z-index: 20; -} - -#input { - width: 210px; - height: 22px; - top: 58px; - left: 30px; - background-color: white; - border-radius: 10px; - border-style: solid; - border-color: white; - position: absolute; - z-index: 10; -} - -#inputCloud { - position: relative; - width: 310px; - height: 150px; - background: url('img/cloud.png'); -} - -#msg { - background-color: #D2EBFC; - color: #1A9BF4; - border-radius: 10px; - width: 300px; - height: 50px; - margin: 5px; - display: flex; - padding-left: 10px; - justify-content: center; - align-items: center; - z-index: 99; -} - -#submit { - font-weight: bold; - background-color: aqua; - color: #1A9BF4; - border-radius: 12px; - width: 100px; - height: 30px; - display: flex; - justify-content: center; - align-items: center; - margin: 5px; - cursor: pointer; -} - -#snippet { - position: absolute; - top: 15%; - left: 30%; - width: 40%; - z-index: 5; -} - -.hljs { - border-radius: 10px; - font-size: 12px; -} diff --git a/examples/messaging/jms-websocket-mp/src/main/resources/application.yaml b/examples/messaging/jms-websocket-mp/src/main/resources/application.yaml deleted file mode 100644 index c0878fff5c8..00000000000 --- a/examples/messaging/jms-websocket-mp/src/main/resources/application.yaml +++ /dev/null @@ -1,49 +0,0 @@ -# -# Copyright (c) 2020, 2021 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: 7001 - host: 0.0.0.0 - static.classpath: - location: /WEB - welcome: index.html - -mp.messaging: - connector.helidon-jms: - jndi: - jms-factory: ConnectionFactory - env-properties: - java.naming.factory.initial: org.apache.activemq.jndi.ActiveMQInitialContextFactory - java.naming.provider.url: tcp://127.0.0.1:61616 - - outgoing: - toJms: - connector: helidon-jms - destination: messaging-queue-topic-2 - type: queue - - incoming: - fromJms: - connector: helidon-jms - destination: messaging-test-queue-1 - session-group-id: session-group-1 - type: queue - - fromJmsSameSession: - connector: helidon-jms - destination: messaging-queue-topic-2 - session-group-id: session-group-1 - type: queue diff --git a/examples/messaging/jms-websocket-mp/src/main/resources/logging.properties b/examples/messaging/jms-websocket-mp/src/main/resources/logging.properties deleted file mode 100644 index 361bf5f6cbc..00000000000 --- a/examples/messaging/jms-websocket-mp/src/main/resources/logging.properties +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright (c) 2020, 2024 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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 diff --git a/examples/messaging/jms-websocket-se/README.md b/examples/messaging/jms-websocket-se/README.md deleted file mode 100644 index 4d8eabba41d..00000000000 --- a/examples/messaging/jms-websocket-se/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Helidon Messaging with JMS Example - -## Prerequisites -* Java 21+ -* Docker -* [ActiveMQ server](../README.md) running on `localhost:61616` - -## Build & Run -```shell -#1. -mvn clean package -#2. -java -jar target/helidon-examples-jms-websocket-se.jar -``` -3. Visit http://localhost:7001 - diff --git a/examples/messaging/jms-websocket-se/pom.xml b/examples/messaging/jms-websocket-se/pom.xml deleted file mode 100644 index 6f59532055e..00000000000 --- a/examples/messaging/jms-websocket-se/pom.xml +++ /dev/null @@ -1,82 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.jms - helidon-examples-jms-websocket-se - 1.0-SNAPSHOT - Helidon Examples Messaging JMS WebSocket SE - - - io.helidon.examples.messaging.se.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver - helidon-webserver-static-content - - - io.helidon.webserver - helidon-webserver-websocket - - - io.helidon.messaging - helidon-messaging - - - io.helidon.messaging.jms - helidon-messaging-jms - - - io.helidon.config - helidon-config-yaml - - - org.apache.activemq - activemq-client - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/Main.java b/examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/Main.java deleted file mode 100644 index 2d46ed70560..00000000000 --- a/examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/Main.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2020, 2024 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.messaging.se; - -import java.io.IOException; -import java.io.InputStream; -import java.util.logging.LogManager; - -import io.helidon.config.Config; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.staticcontent.StaticContentService; -import io.helidon.webserver.websocket.WsRouting; - -/** - * The application main class. - */ -public final class Main { - - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * - * @param args command line arguments. - * @throws IOException if there are problems reading logging properties - */ - public static void main(final String[] args) throws IOException { - startServer(); - } - - /** - * Start the server. - * - * @return the created {@link WebServer} instance - * @throws IOException if there are problems reading logging properties - */ - static WebServer startServer() throws IOException { - // load logging configuration - setupLogging(); - - // By default, this will pick up application.yaml from the classpath - Config config = Config.create(); - - SendingService sendingService = new SendingService(config); - - WebServer server = WebServer.builder() - .routing(routing -> routing - // register static content support (on "/") - .register(StaticContentService.builder("/WEB") - .welcomeFileName("index.html") - .build()) - // register rest endpoint for sending to Jms - .register("/rest/messages", sendingService)) - .addRouting(WsRouting.builder() - .endpoint("/ws/messages", new WebSocketEndpoint())) - .config(config.get("server")) - .build().start(); - - System.out.println("WEB server is up! http://localhost:" + server.port()); - Runtime.getRuntime().addShutdownHook(new Thread(sendingService::shutdown)); - - // Server threads are not daemon. No need to block. Just react. - return server; - } - - /** - * Configure logging from logging.properties file. - */ - private static void setupLogging() throws IOException { - try (InputStream is = Main.class.getResourceAsStream("/logging.properties")) { - LogManager.getLogManager().readConfiguration(is); - } - } -} diff --git a/examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/SendingService.java b/examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/SendingService.java deleted file mode 100644 index 96e09646be5..00000000000 --- a/examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/SendingService.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.messaging.se; - -import io.helidon.config.Config; -import io.helidon.messaging.Channel; -import io.helidon.messaging.Emitter; -import io.helidon.messaging.Messaging; -import io.helidon.messaging.connectors.jms.JmsConnector; -import io.helidon.messaging.connectors.jms.Type; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; - -import org.apache.activemq.jndi.ActiveMQInitialContextFactory; - -class SendingService implements HttpService { - - private final Emitter emitter; - private final Messaging messaging; - - SendingService(Config config) { - - String url = config.get("app.jms.url").asString().get(); - String destination = config.get("app.jms.destination").asString().get(); - - // Prepare channel for connecting processor -> jms connector with specific subscriber configuration, - // channel -> connector mapping is automatic when using JmsConnector.configBuilder() - Channel toJms = Channel.builder() - .subscriberConfig(JmsConnector.configBuilder() - .jndiInitialFactory(ActiveMQInitialContextFactory.class.getName()) - .jndiProviderUrl(url) - .type(Type.QUEUE) - .destination(destination) - .build()) - .build(); - - // Prepare channel for connecting emitter -> processor - Channel toProcessor = Channel.create(); - - // Prepare Jms connector, can be used by any channel - JmsConnector jmsConnector = JmsConnector.create(); - - // Prepare emitter for manual publishing to channel - emitter = Emitter.create(toProcessor); - - // Transforming to upper-case before sending to jms - messaging = Messaging.builder() - .emitter(emitter) - // Processor connect two channels together - .processor(toProcessor, toJms, String::toUpperCase) - .connector(jmsConnector) - .build() - .start(); - } - - /** - * A service registers itself by updating the routing rules. - * - * @param rules the routing rules. - */ - @Override - public void routing(HttpRules rules) { - // Listen for GET /example/send/{msg} - // to send it through messaging to Jms - rules.get("/send/{msg}", (req, res) -> { - String msg = req.path().pathParameters().get("msg"); - System.out.println("Emitting: " + msg); - emitter.send(msg); - res.send(); - }); - } - - /** - * Gracefully terminate messaging. - */ - public void shutdown() { - messaging.stop(); - } -} diff --git a/examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/WebSocketEndpoint.java b/examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/WebSocketEndpoint.java deleted file mode 100644 index 65332fef3af..00000000000 --- a/examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/WebSocketEndpoint.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.messaging.se; - -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.logging.Logger; - -import io.helidon.config.Config; -import io.helidon.messaging.Channel; -import io.helidon.messaging.Messaging; -import io.helidon.messaging.connectors.jms.JmsConnector; -import io.helidon.messaging.connectors.jms.Type; -import io.helidon.websocket.WsListener; -import io.helidon.websocket.WsSession; - -import org.apache.activemq.jndi.ActiveMQInitialContextFactory; - -/** - * WebSocket endpoint. - */ -public class WebSocketEndpoint implements WsListener { - - private static final Logger LOGGER = Logger.getLogger(WebSocketEndpoint.class.getName()); - - private final Map messagingRegister = new HashMap<>(); - private final Config config = Config.create(); - - @Override - public void onOpen(WsSession session) { - System.out.println("Session " + session); - - String url = config.get("app.jms.url").asString().get(); - String destination = config.get("app.jms.destination").asString().get(); - - // Prepare channel for connecting jms connector with specific publisher configuration -> listener, - // channel -> connector mapping is automatic when using JmsConnector.configBuilder() - Channel fromJms = Channel.builder() - .name("from-jms") - .publisherConfig(JmsConnector.configBuilder() - .jndiInitialFactory(ActiveMQInitialContextFactory.class.getName()) - .jndiProviderUrl(url) - .type(Type.QUEUE) - .destination(destination) - .build()) - .build(); - - // Prepare Jms connector, can be used by any channel - JmsConnector jmsConnector = JmsConnector.create(); - - Messaging messaging = Messaging.builder() - .connector(jmsConnector) - .listener(fromJms, payload -> { - System.out.println("Jms says: " + payload); - session.send(payload, false); - }) - .build() - .start(); - - //Save the messaging instance for proper shutdown - // when websocket connection is terminated - messagingRegister.put(session, messaging); - } - - @Override - public void onClose(WsSession session, int status, String reason) { - LOGGER.info("Closing session " + session); - // Properly stop messaging when websocket connection is terminated - Optional.ofNullable(messagingRegister.remove(session)) - .ifPresent(Messaging::stop); - } -} diff --git a/examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/package-info.java b/examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/package-info.java deleted file mode 100644 index 2fccac401c8..00000000000 --- a/examples/messaging/jms-websocket-se/src/main/java/io/helidon/examples/messaging/se/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020, 2021 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. - */ - -/** - * Helidon SE Reactive Messaging with Jms Example. - */ -package io.helidon.examples.messaging.se; diff --git a/examples/messaging/jms-websocket-se/src/main/resources/WEB/favicon.ico b/examples/messaging/jms-websocket-se/src/main/resources/WEB/favicon.ico deleted file mode 100644 index d91659fdb53c934af789e9b93e2d92c679f975d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1230 zcmV;<1Tp)GP)*8l(j8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H11WQRoK~z|Uy_Z{T6lE00e`jX8mqMWtT1?w51zW;RQDQ<{=()Hdzz zw!1sW2fMg*x83dr`hWW7ob&&FCuhEyofXfTJ#V90OB%YTYYw|#iqKDJj0GMwK@Y%Lzb*2G_bGtSTx(vr7!0A-X zHY!8QihhFz^yc-LWJMPj_pR+MShshrgzV#hCzVZx^mxsF+CGF=0g7G^6xo&($5mbY zRU=mL$Bvzg{1cN{v^qesy}_f-QEV5Pufbps^#z|0E2J zJyz}e*Pm0dHv$96aq&}Dc-QIF?TMP7ook+Zwz{~M`igKuIKUO}#-k`(0XumEaWYG1 zxfWQ4oQVxi%aZoGC63%h^D_sdv4n5{-+}5+6kbjPjv=^9XFKynxC}7K!Hw-JUA7_Q z+)_8%CRg@Xzp3!vh!A7s!|gQXuF?{h>9p{@R_W@r42p)=SP6W$Hc<9MUBQV5@k8F-Od+!DwicL++HXZpB zC>zZl3`18KfDYSW!={DO8_kV6_NXo&tq5jB2G*gRNnRbVz7S`AxlUu1Z1memKcl6e@BcFUqZIhcm4*geIb?&ONqhXK8GBAj}^Zx{0VTbCj)n4Q0uQ@WOY3GbL<) z4%~OMZLl?FTJv)B(5m^FE27uGo$Wf+`qR~JkfcvhC=~8aSTtitV5uFpcLBN4SYEbu za$=_8ztA~&bCdx!9ntmCFVD8LwzMq*%w*sp*>U&0XotVnRy}M8lMAL;Cjh;-Fyq)9 zPsW1|6E#io=VeCs3=S+l1BWlMtO?K|y>C7OHf>NCK>gxNa_|4+r0 z&65W0&@qMkW5V{hzyUlfzsOTVTLhUNh2P<^|1aOc>Q2L8Ezli}jT;=Gecy(kQ8oa< safbu=4pe_F$QIK3H*|aCS+%?NUyMb7$(BA=Gynhq07*qoM6N<$f|!R&8~^|S diff --git a/examples/messaging/jms-websocket-se/src/main/resources/WEB/img/arrow-1.png b/examples/messaging/jms-websocket-se/src/main/resources/WEB/img/arrow-1.png deleted file mode 100644 index bbba0aef8a6ce9efc80b64f1820f5eb38d83a209..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18222 zcmZ5{XEa=2)b|*So@fz-5G}+gVbl;r?=2X;mrXv5cH8(EQd-Z6ac|GNuxFI>u`VT$M zcb~Ml>;77J>^z0QlypoO@aG~Tnd0>bp4yu-n&8VE;r0wpDo@I*+?wk+Q2gm~ms(j4 zTx!R?9et%cnnNT#17=NAA#T1cB@dDZypT(g&h1eP)}Wp~VlclvIzHzet8E*<69avT z7zE@>OALE;v#c=Ztkijp-SlYd!>QLj*WDv|m2L;T=Ql;h*rV?x1RZSzPkXejzWwU; zcv@TYjq+uTbzG@-hZLsfr+<8{QAO>AxU%p9%$;wnsR<8&6;UpsOp89d zc!UzT21fnnPC&uj0ugbeJwn#YQQKI&X)MCj3(Hx=4b&8UK22 zX=UL?G#F6xOYa&aDvH;q@}>RY_(03o^&tm#d5NnY=aKPaFEbLmEFddYMLEDUU>9(w zUGbO(OCfSoGV}xhcv=7FhvQc$<%1;>cqyyP6KvoTQoo|Eh_5-plIXnTp-F9&8tWpyos@JCMp0A_%)oXmT_h5c;*j4Zvc4^lH<4>aso#b4am z{apAMoEA)BLnV)c|K97pGzFs!;7w&t?9;pFe$F|+M} zmz58fXATdOPuovdLUdi$n zqY@sAX2@g6Al-X(tF&mQv?oR6FzLBW{oFi!EaBTya~fRfZ9*>aB_KciGf;!O`Z*Lg z>(MVlwcYS49DBee&MJl5PuxeyA`4rJYK_oCkk8};$@!ICc##P+@|9LSj`dmg&O#^f zp8}A-1dx{pBUUb@ESklHnTC6Yp%xl|4xlY!YUM#dnN3SOjs)2+e`y%O*ss-1wC9^V zoJc%%!R;FMc)r>)f($a?&pUK+n;rFX2;T*V~aIwbdq)A=6?9FSe zU`Si|1Sy~-V4MTMEBr7+kALX^42c{DBRZyv_Cwg779uWyNyj6dgiV6|o|i&#twqD~ zyajkoMMs|a6C3fT59LABFAt}frA$Ip5DX8En~Nh~5Hp;iec@J8Yc_|X9fsZzx5x%Y zU>k^Z&Xpf0gC)(S{$ifl^GGiE0dK9!asV_z+R!8;sed1hJ0*jjInf;|aN!^kHKrP` z6pCNf=Iea9?_x}NOF;8%kuc#WZ8KGSa3kO;@bUJW2fVQ-qW#hT(Mt zkyT6>bdrnzW~?a+DLzx z55X(AD+7+`e5UZ^fkISEu)T_|4|fg_I{WY$5<5-#h~FEyh@$<}u7|rgsEdA#7nWV` z^7X<~E_~W;*qiLM?XZ*hw(Q`K2~L}d(H7_0!=Q=R;=KszafsW;cutK!Y6!)R?!D43 zafMtV<-odOiQ%mWh?7=QuK=JS2I96}H!Tj!4;}q36jC;RNey#jIwG%@>RU?$jiqvJ z5dsMYbou`VAQh!WVFZre_u41Xy!biHJ^nxkAL%{^`12P$t?%ypKM@r#4+`K|cY<@h z9rEDpVNYOd4S!vQT|&wSJ{_t|XYnvgfLAwP;6PGoj3Wy-+jtY3%0^mzZE`kKnQ$J8 zf+O)xom)3JU87cjK_Dm?V3I|9%k|o<8DtU*I;I5YTQu1H`+~`>+ocoP7Cl(P40Iyd zw3c{}5^!>kM_L91cPl3`JkX9s!f>eK2e>z{0jH~G2_BhSZyBtuhhug{6MECE>k*}#! z_CT0zOC>w{un-|$knMOT1x@j8QyYjz`TYw0WXS|k*Stem0^`#1H$`p}Ty`zK;|0!s zwvD)=r%ApNT`cNtE0XCP5F|-kM~j*)9ApB$TgOC5n@Ij;*QwMtRDIPKmpgp;@rNnA zHd?6Z zT&X}OZ+7YtY2Dkne?iT^RFgAy0?S(zW=M^Im5We%r86?X19aLsARvyz3hb5~0On~ldeiS|!r z*1CZ!2DaDUcoWn`5xpIVL zCgb%DuF~!!)LYrcW?qF36C8}i26K?$J$9HqB=2&MF?-h2;xZfJiW{1yd6v*Yg>#q| zRWdD^IB~2=?Kb|TI%nco6>mg4;Q3>ax~`}PCk>U@BNC(g_qDF{@!$5!nC^J)yd#A& zm1mfXL!}OHJSpvl=>lv6$EG2_1*Y`bV^^6^>T*u=hgzE&A2B+;T=&WrhDDotOFj{p z?1;y=Hiuuu_OFl5)z@ubEqxDsBggR{ZM)sy=DGp4o940RUvC-(J-LO%mW*SHjK4*0 z;epYZjc#q2Y2F-L=X(-gwRc{**&H@t5wiJDT>K&wOXk z_oFf6ZHc|sE7XKV!7q@IZ#xV>Bu0BE>12gq z7y_-D^I$x+c+8*l#bIs(l{SK240GMRX29=|#xRvxC#Q0WD9_#C?~53YyX(m4pyX32 z_>FvS=uwtb5P%|#MoQ1f#$-K^7f~aRJ4_&#IgX-m|6gCG z@T=bp90surhoLwf1-l>mfGEtcMAi!n2$9w(+8X*{X%Vd~Q1O`&$f# zp}>hg$<{=KB*is`EAxfapMWcxs(`&2=o)2$k?-8$Kw<#wb8R(x=bS}IBOQJ;{6fLM z!zdG?k4Qop85QU-^RO0mGfmwTPJJN2Ne;Z%0;oS9hJw3}jWnHt6l%BZDQ~W?jGgfE zC{~zx`>%1|59R(yzk5gpy>It@WU#w#B}p)t(5i96s=Hg(Gni3^UuQ?Q^x30F`Jc#} zVGQi@HnA`^kZbzz`bTAG9cCa@sVZ@bC3*LaXPc*U>ILj;Uj{eN#rLFUBfyPjx$q9} zS~`+>EJaLQb58GDU`hJLZLPGZKGjHW6iW*66UZvsV=yT6kKX8BE!Abtv6(9&gn*C~ z_EFjhG=6o$l?5{TPkV|HeHtL8 zfw^sXyEu5N>bOx==d?H$@JQ;3sIY}09wSs`jBt%r;2du0brlR;5ZOHS9{6=#f6%Tx z=TXKHs|PfS^lfhq81K-r8E_K6u#%jML^;k1;XoooHKQF;TGYZo;CJ_5K$GuK_WeYp znLVIjb0Y^P@qUXX_hCG?Rp-;l&(XMtGhxkC!z8ULxQ^|1I~#(UB;YDaf_K@?4f0j5 zTav}-H+bkBT%gq##0Xt7@rPHiep3h<6L|J-u25)|mD$_xQrvXhvi?5Q6lqmaOtElw zX#}ob__51ahMDI0*@bZRyEjEZklcf!+8v8W-wND`DIjC7gSBhtLE&qJVD(KGvcJI) zi@xEH&4x%T;rZR;IVu9_H(psHZS&8^Lo>e11o31K=eza;;l`Va2@`9EKkgo@Fbp#( zCAG`0bt*H@%dWXywmhXlt&X2M75ViytBl*(OTLtPan3O=QaX7P?X{#lWnsP1ok+!* z#PNu{^-y?cWo1gJ$V+n6jB`yCESs-EHD34ao#s;(hbaO4m0ypq2*?KVdpTzYD|3~y zcu#BW)`iK)pV~No5!3mOQvx+_$+~uyhawa35`6a9l)4xH|d3 zZKKoij63TlK4<^G0ABW%xhKF82kkwPK+Hn}N1SQlXlU_jsUC-m$}Bp4@bo(O9bV$D zMXX)xQ;3E6WU_J6ru8UWrF*mT+5)p@57|#|q;})BVmpBw!==rbX;dA2=azc$XUCAZfJ{8y(kI|{=!hN&Z^BD`&*M5iv#)2q& z*T#;AMmm?8J-7w4dzaPJ?N9>xN72LMZ{T=iO}{a2X-G(gcjDy5;~7>(NSoQN?EG=$ z-AlzmsTQ@OI#rtG#1~rp2HRgeD?+lQ2AX}Z%+%=#ry;oGGtBhG^UHU?H3yZ=i)ALt zajsJsEDM_Z9Hbj!5FSX&wyfpPvAYWf^p*zWq@MJSWgrdMPcI{ltXzFX20^2jxy}u0 zW9Ea33x;T;qMIXvKYr!m(bIYN{tFPIEM`zSjjEj~H`D&(>jOxzD{5p#7?z+3Gf_Vq z*{oo}q4C>7q$$cT?Xew=OuAA@3&u>nqQVg3SeK7*N*Ud`lU-1(>~)w4U#wPN)KG1v z-Rj{U2QM@-ko;xjo-o}bn^K>8OF-f*HH9{2>l+$W2L7i&)|1~R^L&RP^s~=Rc~WcZ z?ML6bL;m%tuttf$i?K{5CMAO#WZ84D-`O#qvl>%!$4S0C#u9+mz}&6i1Dy|9MBBri zs`=^FF0Ca@co*Q%g7>)BCgC=5pe|33mX{7ROU!*gzG*=S|K_kOtlz?x1BtPeZO0?(39FI-YWeM+U>tLugx#-p!9-P+K| zvIhiHVyB{)dvs10{#3PY!E5uUhFbfm2we!ya@pXf)LD@0Nm6SkW{-)_+@oZq&-ly` zQK$bEGS1tw6*_Qx8kquyjwSr8v~(L-0r{o0je%* zGhu$%F6>GE$KXDWO1LzPbqo#fm>Q94ZhHB>>-cZ{RAo|L~XoF6w45IQ7& zM+Q=!Ivm~SM%t1m%mvTD-nrBJzJMorM$}E=15H`s`hxOBYlJY5^v(9%?ZcO-tfs4} zvG{Wa*Ut@Jm+m=Xq6*S)<%<5C2XrJ4hCU05{r)4xoL!rmky?H-l{4;n-1qIy@0|2c z`v%r2dG=5%K4vWb!G&7>snaT* zHg(0A`+ef|fw4Aqz27D3RowSnMQyK7E3PV8q3N7)@SW>)dF``8&bZR{KX#NDSnPL) zsvtUponhYA@|5}nC$iL_l`C~^Rt+}Cd2zd)tRdR3HB zh7nSoV;?h*eiB=eHv5~?dUAkdy7wX)~%2w`sHyc)N|r8RCx?Li*adz zVY)JvDeL~fkGEazwltM&A8MfA?Tt$?E3_lE_vvEpi=}!2tCKB^6woq>!ExazN`t34hw3pN6k-3wys6x(C)23mO&oot%n`q?)c28ocZfQQ!9_+H?U z%4g87kYOFUJt$$q#yxigvq~sE7{#Gz6+Y=NKu|^b`89KFZm-ry_*C9o1+RSx?Jf~E z5Dv29fj6y0q2c1O(C~^(8(OC{o>ocIHtY6d>@~^&c7p>PFu|Ghu7JVqniUt0)ey>^ z6x<^EX=~4~Z=xz69Ik9CfEYN#oN?vp5^I>v#(2GBgr81i^S4a<_Dqffq3@*_LU3(i ziLj-R5~J1JbLy0ZYBP{^HDEtqfVDHvGih(VO*M8-=}y;T{CevvcDHI%%U{MO`m3lJ zcyzwjrp~66pZugv-TpG}yX@JrDy8$-!9qv-oGyj@q(RU2a=~fS?ybwZiLbo&`#_1`%|g z<%?0AaUDhWGSu=^-#JUCG5goIH0_<7ao^4DEN8@PmQIiFBy-{ld0f~8d#?DLw%hQc z(s+=t(D+T8nW6WmH=tXvYF1IBfd1Ice^cPGsH!hwO?q=RCR@Liko^`%WX>CDejV5_ij}|Y-)`OYG%-lKjqIgQ zIh<&&>%y^2&5>=Ez7q;=c$S^c1!JqEWaRi8S~n1{Ip}%~f$zJe67&Shv$Yu%^vFPu z%~ZBd*$@rSyejPd3%Vq(n;&DN!#_My+ft)zZKw+yw^edZ4G3)?9BA^ zi07o_!%UtL`>S)@o=x;KY9_J8{I=;>!v=W^pJw~YnJKZAkfe9M-tX$6&lfq@)i#{> zjD(e~*@3yUo}MSc;d7T1B14_xwA}a^`>>=m`EQ5FPm;!!ek1u%8Z<^Sm3_)xRT8ku zxdp+<b3DZ9_se;X~3NkhdKw@5X( zeKn%#ysAET41$+o)_Gf1hSg3x4#Ps>ik&yMo4Tlb+|^XL=cj=5ZMtk_3`>_d1;{mE zf#dHXqDhOr0>>Bi{91EEmO*8y)-NLjjIl09$Bh_O7xZ=p3ZHjIXx? z=19mjiMH*j_@+Ay0S=RIJ5z*zeA(|bVqTDqES8_U=K>e+N46ZKQCErU0-W-E$wqYJ z8kfEuuJ9%!zndx$^fJ$H^StWVkVmd9)wc)* zt?(r#68v17b}qKTi%59B@#&gk3GFps>pECP%RUn-nf){(?<^DYn=7c5^@sVVdzK z>yAhZg(F%O`dihD<`fVxSIR2NMr9<15@!>*E?+d3PV`sc+hQ$%`f(U5WJi*{HUJl{ zt%c0H%LgF$(;rE$sm7l64E2)UsTIkUFpM1zHN2IHJO$hhRMrmP2vNZUrBn*KYDyo+ z#*GT(ZmFc*>Myv|LrV-c@^5AAGOPg)pPE9^V**Zg)6Fj|TRS>Ist)8p?!&;wiZ?!qRjr1u;#-1|9rmYu;eG#SS0b^gMigY0_mboVQzC1~pZD&F> zjr}K<(T3&ii%6l^!6d0Kd<2{Sz-5ei61D&B?x{-to^qCE13`BBuOBl2Qy%)(Do4p# z|B;pOl{KacmuIo6PwifI+z=ho7g0V9NSp(h%Pd9t#Di>pjn*qZ&q%B7yxIG({%YjS zhPkNGJi8}cC9PSbz#?3y@#HLUqucb;IW=@W+m&wixTubV#sg?tOol(<99^f}zFLNG z6dCn+_=B?VmVD{arno#d{doUP^%xPO`qIyOJ{wl}%GA51raz?F_HgHiD#tvwxs9{d z@aJo=g=f{D9H)_^rZ*)QW+P*Vy|1`UeE>w?H{LT|YOKG{m_{XR{r#AX>d9}w47*A^ zi~qFG>Ub3tzN8L%vQmE?516Bz`>*ctM%b$&(NT{pzG)%P#PreN@D+2GQI7aosypuK+lUi{&*`d5JxmBH6bHL1ixfS7wbA-zp$ z<>$^u$2ID29hcG_|ILI&4oLiqzf}3>I${y!ckk4qdx`fT+FqbP7CfIm}s2b zdJUFeYrJ8p$Vt{MGrY#TTjjK}pr^_FmtnU``I(@;WvdP{18cb-jP=aopxGY_&&ViT zUYTGEtGf`91Cw@JY2Cz={^L1n2%Ryz}g#13Z$e zvYziA^U6@bNN=6uo<-Ix4m+@p%utco8dVm8d%G6_ z&dgqaH1I0`VbdR&IZ-ha05n=2dHFJlU+p%-5}1~u93 zJELgkgd0`%jI&4b-pI$a@u&;KS9m`CHm{*oeT?L-DU1|FLBj0FHv@Y<-)2|SCKz{~ z5C9b_pqYpqA7mjS=#*JBj|)7pv#{Q>Vv$+1_r?@y%ivD2sABps<8f%a2e^j4 z;*OmQbI*1u@*lh4CmZ_{tNJnY8_}N~8GczhXMJ#3(G8;fmvxFl?6N;YzM`pp`VgL= zkn*Y|;=wqZnf_79R!GN+@8B6Swim{*|95V*)11EVwGGKYyPbo-Ranx~vhyEFk}fGS zvH#eT{APBW)ZfIG3P*P}T;J1PE# zrMtP=O=gW>{JFB--1~S2;Sd9>9SG^o?TXR)>ojjRLFh-%QOiY4!4cQ;8A`6lAg-0 zR6%>oy|oW4geK!CQuvWSodTa`?<)gF2M$V+H(sBwmN%;^27Q^V*Y>}xJN)-$Uynw9 zQp|C;P9pAm@r>gS`NVz^JJ{nh==xpOR^Rn6fa#%9z3w&Ei9C0d2=Rgkvc!F-sx`T( z(55E4ypYrxU1k;1$SvHLx-eo5E{W+^95ZKGU6MPZIUnJjStS9q&v z#k6YOA|d^1rpAcMz!u1$ivUW2;!^xW-}dI~g@&i@i*p9`E(Ie32G$QzIWh#tEVVMz z)F^-b2tC21nKeJ71cY%-P#wV!0ff9~EY)*+hfdT9#iJfdCIX#%gOL@-@;4e>H0lqv zZ>74e@l{bPgqMLIe`4@cxX(*f|9vnZ%Fra|^L<_rBjXtXGI|0RKjovRHm1@zTJTRkE9w1yEfQb%I}Bgg^iGY(ol5{ZX^{Q91_52T!)w3jt-({Es3PW9 z2HbjtDd0pFl}@cE%?Keh9x&wgMunTChkTy40`3w;*-bj06z)W5@$%H8_Xv?Rqs&Yl z+iq@90EdsiRh1P{LFkhd6FQ$aaE>~1RYWrrNkGfjG{)sN4I6ZG&wk0P0z?OG-e=<| zFZx7WW#K`btY&CH3pc9<5kr2g?zZVA(lS>BUHX>-0zuQ|IbK1$ZTu4# zeRAIvSkK8{8l|*bHPS^2fjK)HvCW4--2Yn(a1peg`iJ?`cUTKh?db^!p7R#8>#ze+ zs$f{BdCZ^abx>zmG`_1-LS6Dcpqfc0x=w=#zT(+Yd1E7XTS@9?piX*2MEKBC6Jubp z|Dks9H4emdTp$0XX@>nkC~V6420*h)%TqLnkIx;W`#$T{^KSH$59jY$!ZD1lKnD3G zTTfazDmd#Puq24tCgLkb^Z@1c;n&lGlvn@(tvQt~&Lm%T&B7gis-`_18;opV&bG3= z*wgbcDCKf^(<@3t zyOU09Lduek-a1|8s1mu8EEu2y;6b04H_JwT>bu=kjEs}IYcCv3fi;YiUVZ>geHG7% zw+-a8UTjeBlHm42Z?H%gSmwa@L!@STPE^E(sseA|BywpUqN9=Q+;~v}2_YIpY;@~v zqpa0a0E6=#+%=PRA^tR-aG`zLKZw#aT$8A#qGPVD{Udi4vOFehnXdYtUQ^FPf8+)e zxH}-~%KJK!hYJxmN5ZCBC{%0(ISsWmb)t!#p#6l;T~-&Ib-&si@43gGm(ag%IBvE1 zpHn;|M7G1D_RX3NPJ$|las#gT`!uCbN)cDUF^2Nn3$gFp$pt!@r`s3Pz|jxT!?4Ig zc2)e+O=#BRz^J4PTM6#QiKpj?z|ex^72u(Z!T^P{H9fmUi@^tEd1 z*u8p}D7Tw>+JpcXS%JCZmU9}YS#fK~KqxIK6;zrseVdD}5?V{*AEmk@*SUhuH^unj z6xc%NkpD@t@e7>nCcV&jY82tU59`k8fdlB`?7kV5zM9t7vu&ZvPcr6L7!hkEu<(cF z+q5M9G-6!lo5nbTE8WH11hmcm30Iy>RXAuxos%}Hgmr#xl3JW$dDP%#{de@c=bt2j zaW%3qF1*w7;*Zknr&1Qj(dSUASY;@6u%;#}&u6BIq$fePHb5TSgQPr3p?{5U3F2E5 zX7G-lAgo%Ib(?5Mtf36{;A}yL8f83__&y3~E}37F-RM0R+&jq*RTsqH<8J zvQ%x(V9v(pr%Kixyn-D{92{%67>)Xr`yBL2r{ou0qG|t8`RT}K;8i6wuw)1LZ-tiR zUqVbc2IahExbdNBGO9k<=zH)Sr3x-F6=WHwsD(q2z&L81ZSCkUQjJK<*fedvU(i#B zR&tTqbAyL0i_l5+hI}Fi=IW&Rn0qvOafMl(pGkF$A-WgwHtbyft>Wb=1uWUKeszRb zy0(}jk%_7*t3eE15GFlMa^Z|i<0QJYILk~XNXAV^8{PY2rMOG?KZH|1F4gxR`5cnv z5Oceg3g~!5=fJO}2)z&2-ZHE<$Y9W}o#&T2<;twu|E}*{0?fb7QLD4;;|R!7Ll$L( ziZ_!P*5%TE5#Z~7vkMg|BQpc7PHWPAhODu zD9dJ2v`}F8;3s@LgB$(JdijGRUJvLhNS;eJ$zx^gH|dNJT_fa@1*Jxz-|pXFx1#3( ze`!mn#*Iq4sP{V9$x0T`nDfs*xb${bj%R0i>oXU^)8mq}P`zGf3x#)q5**D7f_M2Z z+#Z7sTw~vw>nG&VrGD}BRxfHjdvLb!^gd1=8re>R{~qF@dQD^obqRp=LS5K5jFqdIz)j4y&2x|N{JpVRCcBDkRD{4lW^ z3mli7;&6h*?nSe=z+)`@Ix=K*`RQ;>mADi#SuDyYz~Uy69O>4%eb5FU1e*}LPt7HDIs*%Ma1XI55;`MDnK6BELEVlB%I25&l?c^q9~bZ}_r44)t@|wdX*K%b zxwu&&;4E(7)AwJZ_=X2rc?GO%hk9RkYJ~_JHkw=&t6C17XT#e1(>3302stFGrkg*xSXtr8jb_;LU?h&q>>gSYyY9Qd$Q zd1PEl$ik#+)=l%YVB_(xwBXH+Z!A?LgpHO&*#tZO;NFPL{+)K!T)N1@#WrJUG3_nq zXc5FOOSL~gtnk%k=B5cHNKi{z+Qmq!lttG zi^WxkpI+R!zlIOz<&k|tdv4h-0xLErobV7Y^9cz4`t$~^Xh>*PFlDIcU^jN6QnrG3 zQ5kBz0$JmqqnZ(-zI(6KnO!{YMI3W6_yvmf`yuMpT+W*qBH(l%0QurW&L%*U@kn+a zV-1l$=yEWa+h#~e@&OyO&TiF{7pOl9Z7$|PTj^9y_y>>bfHPW^7rD>DA+bWw=bv#) z{$rl4{*x}d6vXpk!t0yMEE_aOoC4?s;U9bIchF@;(QR9#4o>Nx3jZnreyU}5cAFLj z1_YWGEqsM8OhyKTU?!Vi_uG9YkS9P|?NC$`bCZ4Owt8aT^JDrUC3cb}dVVGzl47fT z^uhu8qQd>3+Mo6pI|7?-+=OzpB))8l6fnO7U#~=#IMk?g--1El?kcMs7FqLUbSke!g)xrn&D&h&Y(-rKC6;1Tv=#4)pzRmNiftKsaZSeq>F4vwoHZ*By#ORpPdSvhsi{<8x%kt2 z|8mQVpAP4SK(%JbFgKL1@iay?`|zt&E%%WpSkslX0Wf>$!4N7g|68rPfRF>fF>jX) z-55xm;XL}LhPugiIY;q?2EHz3&N0gvAW3qIt7_yOe=07uNsMq+wCJ^;j(u}lIb)3@r^6@+`fbR}*{)&bfw^RW}WZU-`^glD_b`KV;_J zH;XN#xKooB>p8tM>l_gmQ32uma)CEOD9j1>AmzJv9#nQhd*JK z5BSCs2?|g#!bh0Zo(C8qZQ56uwi&G{j^l7dhAs`Gwa4X~3oO1N?J4wO&3b}=GEEVt z^K}ZY=+u2t>@Iu=+zc&i#%%ZT1Qbe{rWCoNgsB zO*~(WjgU2-TJ9X+ZvFGM?c4nP%irQRiK?Ku3R{=%lz1jS{oHi}gYlDt>41i`>dj3> zZ8;~#Cnogjk92wdjxvvLUY@<20Ldt*8VAW8=JwaHgz)9PXM^|>J3T;_0}l&iZgO8q zaXBD?{4)*4*D9(T-x}s$S>+Mse~Y$sDK)cM^veHoL5FF-yfIAv1w|U+{VDN#@0jv1 z{4z7+$eRUWa|n2d^ZqVlVT8Gofr<0gAB!r$SOKOVdjo(DaWbiQ-){b9+_^6?{>#1u zbwtk0WNBo*tE1U%@=U?pcCx;F=!S|QIX-i_2KEP44d6-S7IDJq8EBZNZ)BFUbJGgb z&n#BW2xjFrNXgE0oZFG=&^3?e#{#i$tOv9BV#u46KFU-CrQ6$dcw6j+a#`$!0Uz<2%E9)fus>sRu1brt~i z$93}NWdCG98csAWT5&UDVcLVn5*6#Z=UlKa9Ob0foaN!y?-0J~P^-NnX*|3^n8*1S zz;?X#MZR-yi|gBWCX~-NXc3Z|Z)xONy1(lFlq>+H{-8`uawej~1yP3E;+=Jz*ZxZK$p2^D{X#2Spyg0!r{kN$!5 zlRdLXL=`#ZfPIlrqCU2A8vE>qPUZ2yax9uqy0r+-xBOL_o|YSzvH67z=W|F2B`EuS zOQxXu0NPcnr7@luoE#Lo&fyl{P2qS|>Ma`SKTE)2=t^5Fks2WOuL6oah=RTv#iPJA zM*W?OuTBWB2hMdsUo3#YGM-+jyDgdNJ%Cn_dErYWSMr7%EQK5O9${b2QpY7wwnc^c zA?7lbpgkr81)=@Gn|7{kES-6<2(R6B03;9xa@bGI<^JlN^aSONqWD|kYiqn>>@k%sk6}w^|UUJagAO$ zZ5yR(rp%fcQZz>FogCUPu3$qf!@eERl_X5ONA`MReE-8?j{sbd7MEs_%~LzLv(FAV z>s^GW+B(l-g|0yJ)2Wt};JuZjC^w)I0G>=FEShOu=%}E8wU)px#BUE)+Y{@9-k}^P zIpXquY(bH_iQ=DO-Klq~BzGcY$RfW&viQGD%*+hZOGOQMyMbFbue51Shh18UjLCgr zz!aHjJUT!1>GAg$YzY*LxWigz984JH@c$%<+`zq4)=6Kt{N;0*!tv!4m7aaIM&RQk zRHz{8Qo!C`*V{{f1^HywNADX3*jjO%jE$pvt?ei;19KvUsBX&#a9)a7*Nc4+>mvJ| zx`VCw4=6TFEfMvnZ8hZCM=>cdHCnj9KEp0DVgPdq-Fhyr)}4nFzugjxh`8QQfw|qv>xpGAdncK+CGXqgQ9bEtXPic3xuu==|qa zzO_Z~T#~f8@RrVcwunTOfT}UtLtsX5mw4<8Q68Q2+L@kWW(UAr)5CN9Za#kXFpo6ABq{kQ?+Kt|ASK7wta4~P+j;dlx-D5 zBQ7%YqubFpqKK%*`hFm(#^J7@i(z_Gy0#YWfq!I7fxD_1guy_gPCa|#XOn)}XV$mp zwYXxt5r7ugL$TxV>4r$@xVA2{NPPBw)x~l)vlr+=7j!3)Gb8OE;i;RTHi)K7eHob? znw%dKfIINk>es=~xakzx2fBpUfodU1yBdO~Xh*8G=NCyRBGru`xTt-_|FoRsMttKN zsdy_e?}(}wT-?abdS_B{rMV7@xB*^Tmk}~g?-4+AF~jF~#i$%yrY?bkNPile8<3Z9 zVs$<{Uhv+ZrO3jbgs)edb-j*{r7c`?czb9Pu|;+I)BmXt84$%N5~x!Zm_vRhrQim0 zI-%YPVp^Aq9xlmKOaw5jECfmUo}OnuIJWpSb0vLNQdpIlcVF9ZPp*6DS{Qp6=3f5YQ2Vhr1isUT(h6w=AZ6hD6}3ADes3H~_c_9XG!8qXXXX;v zle)@(t_vli2WyOYdsJ|ZP(gKzu{*o3r!-_ce5LuvPe}QL3;k0QjQEnpKxMJVJAXJR zfUE^V9WPFY3vU~7T?wg^ahcHYCAVJZMk}z%1Vkq45oaI;xl2m3kP*O;_;&0jhz0KG zNju9|VKNr-NgDFh`1QUaSka}HFrpPmL0+&r5Z2WJNf3DZh#M9nHvBdn_c4*$m~&>_ zWJ6DYDp3PG{hiQFtp^_)88!&LR zjY*e|?xU9_ge>n*_uDPVT|sKY_y+mhxrwEhe$u!&rFI`83pFW~Rusd}eIMm<@w-ef zf|w+a{QIpXi0(o2ucbjp zM>xvmEK=)+%zg_zn;!yZwc+h);^=+A%3{rVe6G&|G4h5)bnKEY*LF1>MN^MIJ;bFo z<`2e|QFMLD-)PY_?n^}I-Lvyr*&<;aC5ctz5Lni}OJL?7lMkjyR1acE)8aVO*9K0e zxwlJ2eDh@Lkb)BfoO>^cZ(`M1z$HYa+P9>f^w4R&yTA}GH2tIN8W8pxc3`nT_3jj9 zRfjciq)Tgu1f2!kh&-Zm+()|5h^;H=Q=~B1v`8h_Jdxd&CAxDt^UF&s1kf7W!9^Mu zI!(29CZmR7!1-fWu5ZUa`%td;b_m;ygE%#KM9wcDFuml#I0_X;vuRS{pMsS_{s{-S zEi6#2JgCzO&PGj+NC9}e#Xq!I)mqp56HteGCS{_$oo1g79g<@?e~ITKU27VDjw`Cm zEG~oGByx^Tth!v|e^)I1glO zb(G&TT;w|A`_k$-`_f9)Ye@woBpInm#U=#`^`-yuCaR)^Bdsq0QE%mM?HQ9k-Gn=g z_oJT{CA>xjEi0y5uumKjZe&@=g!-H%bA^3?;6UUR=+A_sbWPI`VL~^VCF+-!s@ciC z0(eE1?nuKP1Yi`Mi~owCyuZ3Uj5Ca5AO%-Vc=QX29QHWkHFRj?E&WllRoAH4vdK@- z8aSL3=anwuxUdZ#^$Xa<@VMg8h)3;ih$JB4neq9`joLSfVE~e4N}{<2(fWGE2<4}$ z!e_9R<-GfAivnO#cRKPe2#)2*3h8}m_;kyJ4*ux0RJhT4b3EPJ>&ywL#(LCnd2UBs z@Si_GodVbH&1kJRdM@UTb4%DJt#kHhZMc11F!Hi}6dH-fTBhF3Lu`EYrn-o}9@;+= zh=*iF39B1Jl7bXU@XP99ygisFziWYW!pd=CPj%smakCAYmUjR^WiPZk4drcLT0JyM z7u&rY!81L{aq6OswM5_fmrI=ltP4#wPJ~;B)GkF3J@cDMAzZFS2A-^yL(eBR9sG|Hbg6P3vCRhf_`O>!z)P@85Hn5^5|d)I z9#z<_wT~Ij#kv~Q5HUCY*`r%(Fo{K6-Jn3Z``Rn8ss*G0gw3`$qsL!wIe#Rmj9|fw z(4_Ivj45xj88Ob_wlO>(1J zIQ{_PR4DMKHu@JN)qSFzIC46>JJcJ;b|F6 zd8&dqCNtQqL;DC8LEU!vNB^}kcdhdaeM+|<*j`8Iy!5Az3pV&>TXIlVU>It?h6-!; zbsXMm;5Wdx-jzQ-H5TY^*cQSq+qgy6jgZmqw<$BfN+0y`(z6XPBB9{kJhHF)LFcvv*?&}y9lnmv(TK;><9 zL#^y^^*e6M0SzTB9JTaLab}T|6MPPx?1e=*d<4shi#QMOnw^C(J z0)f}3E~}8yY3C3-5SHBUWX3ZHU;(gk;X(U?Hu^Sy zn~Al^ba4XDce`(S%3t(JZLYR)se833f(pV3u!lGOn^T#={Rb6coH`Rh<%jONbxJMrjjkwxzF)_`0SGNith=LR1+gf1n*2(a)7{g zbW1Z$Oc?Y02DP{dfT5D80cTh_lkiqQ@5(%&xy4XZ`t!JZCUy*)v`O^+^#fzVi(Nnt z?#jywPxgi{Ydlbrg^*+I)G|gqbt*QdUOk(Ycw7APewtG6KZWW@jE}`rm)0LxrFp;B zOg(^wrhI4g4%v$olSgdk5KZi=IeUn}U42T`>d6Fp|Dp;;g87H$6LaUGw_DiLf3HAc z-Et99BjL4;v=SPu@+imhBmGfzBMjkx{1epQ$l!I!9lqg#jv;m*+GNMtAE)H>_=8NI zM2o7YFmM=sl)u;Prun{XZfBSs^jze>m57SLW@;!FF3e_ThVYilU$rOt3=K#Bk9^`2 zdNKs6nYZN8BB&n^r@v3O*>kvjSq$}ERwz8nt71N4*JHO(MMw+TenahoI_UeJO{McNfilDj!C;xTd2*F^Gcsk)3 z!e(0H3Xp})!FLy+&reXKNXJd!Fhlt>90evw8b`AGeCQQ-n?1K%JN&VQZR1Ym6VUEZ zi)yM(=f#7sj?u$yX>+OC7XInAvq$sI~q3L;M&0t z!y;Nx*&kXk&Z*kkG};^MUwEwjp8zuk%=vmOt!5%tXY(#B3*c>XuxC91Lsvj>pXFPC zGni*VoU~(+{{4s-sNGke%@8ntg|TdNfU#I{+Ty-2xpH-<$;UWN08MerWZ(jfCEExb zEU-i}zqSz5$thrO;#Hl&dIrqL=;$6vZzyC3oP5g=2%sr$Nnxq}d&>lKUH%tgEZO5& zhO-;l>#<(V3$S*yzwZrTc2oo9OQv%GO>s*JF|AxdoH{c}&i~FHU?Si(Y}vr;fTu+c z?64^|mw8J9{{0Vj; zMnxC>0}E2TQi0`?HDGBp=>J*)#vdOUY<-%t!MMnsx$4M{gLci_QmAEohqJl;K!Ev(vEB=1Ca6JW;0FDD780T@dI$&DGH_P&Y5D1_t!if^gYJLDqmx*Ma zm3H&JF9Saek1v>K#VBqu+9x~^bqAR10$>7YidoB)%4c~AYoO7rS64F9`+m_&V9$z6 z4#IjdyTY-bU>N|1U`@<(Nrk7S0%*b`C@NWvt(Unww${uivD*KqbL{^lmZ&)~Jh}jy zVwJ5J^X2Mf+OSN3bpl2+al}7`l?ObLFBhLLEL!ksic2anrfj`{auU|Fc{dLzZJzIv zH@-|hwWkfBDK43eWdO{^Dm7OU=bRxeQ^_CCxl7_&Bx zJYmdw(=V;RB?LE%OUi+{Se#}9*4OL~I(PlQ6S!R9swD1E6C@A;MJX-B9b{%X}`iNaV2=2_9o$yn!@N;&pzY+KIkzc0rEnI-ga!Px+s zAcZ8m0Ow&#Xn@tvlx8v8Qdsl9M&MR#C4lzu_yTB(QPyDW7+8y@W^BPGuvN?!c&6JE zz>UE3*fN1Z0%(fX`M*w@V;PnTbFBQB<-p&tr8CxIYi8aZ9$5fQvCCHAFEYK#u+;xm zSY_sV;9F#`p9vB`Q`Eobr?6JDqp*zShXtDXgy3ZWO^|KmYrva6MFw0J9#sHM5R)d1T6V2tn}K7n7EN2RjDYYv2cITLLf-QJUyXIk+$6w& zQP4s9NJ0yzp)K>UmCF|B{W@u${~@Hs1keP@>dUMEb^;y)-c6{73FcXlE@cW<|BuYE zQQ?sUA|OcDQU@%RDON3~KSYm2@)iLCP2pp;t0+lhV~}FN!NFn6%0SiN;NTg63k3}YSeeN~GX_3{*+@vJ$Vy01 ze|B;DWMgj$2gi`)pClyHElS>FtY4(bgmX;2k(kG?i^sZAs>vW8uEPBLz{F*rnA=81 z&43(vHYAiPRuh%j%8nkbs{SHWM2VDgOI`1b7lnr)=Eb@Z7JB_(74E=N>w$gLZ^LY=+x z+im3Wuc}rW!G`OGb10k4Q@{KCHqXfW$Y((=TMMqszp7?=Q#~%kwZHP-&_|iaz*O5s zc7Jtw$JXjq*4_x+V|F7uSbjg`mQL&fr%{Us#ql$hc8OT*U;nJf=uCX$b_{i8Vn+6h8sghL?JqQ@Z;njoUKUZ1fY0#{BU z55L|K8p#q0Ta`dYE2_Z>oP=_-g-kp_?mjzF@GaLvu^?U(^26-X%EBYBKisb=%?A`- zUZh^Rl(v)e6BSRV*KC{HTSUbem-N!3AECf&K{1n;hQdw49l|}UR^k!?E9jqPbY0=# z*l7Q|;Ju1OJb*=1H(5nV)Gb6b0#=G2M43sz(pxu49XAOl2M0?>H#i9wOH(&X3u;dr zH*0EXSw$7?U>ssNIBGaqsF;S=!cmr|7op`%pNQ)ub>Y{s76QgRbhM8usvuuPW+Hn# z!$qd%=7&kcA()+{{aj0K6j(CRsPLPLq>myz!hX|j_A1rscMCLld>M{+r?=iK^gOOs zJ4(KznHNI4L6T)Pw$n_|zwsa9- zo;6-X{nxeene)>>5@s1DFBZe*l&~;mdx&q=YkA?~+mIg3j~D8G+s{uJMRmZ%60;ZE%~sur>kxEVv5SFv zzmQplPZ~$D88#X^pwt|pa_C2UOL#~PfBU0hsX|F&>Y zLNzx8iCA<@sFW~c-4ACp8IQXO>lYiGM0Q5sLm;V(P94j_g+$Z%9ZwhXsc)42m?Sc@ zHzmIKE5Vzrhumv!WC}m*(LUDbX|T86ZNzGhcwU~=G{EgG6n^ZB{PVRZ7WS`cI7?tw z`1dr{^v9Ulj=;c^rrm5NPouj0d>I(NcrJD1G;)m~U(;ZwegdVCjI6Bb+1ekE9X$;P z`?;DtIjIie$F0pS*VgA^GT0U$3IhB};H&>5p1y|S)5Br4CO=f=Mkc#v%UFbvEsCzFR9n~y@A)vJ{*hTug1Zw&41syjwOJ9n+>KgPV>8O z9p^bAjMdp7RC0{B!Mw5;>m4>>@}^)7U`kk4eS!hG z2~nU>Rr`Z21_nlj3DX~{>pclv4)2L~?NoekK=Y@~?iFM>oy!f&YVU`IK&HUP8n}&1 zdVD3PMJtP;hnRLDnVFj(FSACRoqaaj++;i>J{z{m`8?vii%*3=yt7L8CK=Zh5-x>) z{(IjIVfRYJsl!1MsgLhQey*>#*X4fun|h0fLvI3=6BR~mL9A}=CtZjATv81>xICZA zCAux41g8=F1YtEVY<7Wa<7o6|&0`;h4DJCXlGuVs&lT@JjC_%|uZ^##zuDvV!pDl7 z1=-uqTEEwHJc%0_8JR9t-e2yVUn+|@?^g1-p7U9Kcxv-3&)jb??M8XHJ$0f_knGt2 zHn7iFvOr~9Z|vmQ)UAR{N-Zn#*&5YzHGrAIw!6x(C0)dcay5Zm3`wQ?T6vn&XBP2x zNpm|)!_kqAz5Omf3ra*72}Gz4yhaSaoac&JOj}de0LAb%zvEI(@YR(YDV$<#u~Not!gKAl1he%aSNxx!{3C?kEY59V9$>F@SJ*ITb&P{Z|-iN~+O*6;)b1bBpm zJs#BUrrdDx>?t)F&MYe#Vzz@LOuqgj!jJYdmHN`F?f%EzW~#y@!hVg@@p9^am10{6 zXEXU{uvbT??6Cf2a%L5a`YKajO({9R&(->RrgmuY@$m`XF1dQR=#sy6Y`@=Ol4oK$ z{pow__~yF#{d?Yb?;rM5$n*&GX9%p3rx1bIKf4upmGbcT$SB~c)nX^)xWp?kz=A`? z$jGR5m*Qf-()yiKg;A+7Hmr92R^BO{P%-r6eGL)^H<#V8(aL;ag$C-51u5`=#t?AA126~m1c z$@=AaTs`-L{(ToJhr+v)j|t-#yxiT=N>hUii;5>izkPYSS+sS1?u~nEPQR+!%lWP4 z^W$*?7m%_rWLtovf$@bDk`Lt5BE8igFYCg8g^jnd<94>URSTrPbiF3OA^$oV?lGR& zfon??d-A>n`QGNrx~sbzgzhrZ^gQ3<$^HiGqWgAryx2kCC(F&HE`y`v^+jOT&@;;c zY^(Y~OyZe1QK3j}G_81TX07>gxF)M3VeWd5y<} z{0uAOJa5N3VpG= z$otUYOglH3-1Oj8MXhqtImqxEo3Xv%tP2lYtg*>U5ULt5ex^RWB6dPLg-t%x5I17T zd?vR->Y^fRee znuuWH^?@%B?m*-bHML#vAXFRXTBXTD{JdC%cVd2 zh=*ALucpD}E8U@t56aKaM?*(<1|AYQ1Q{7QEG%V}6(1CV`?{u#tP#EVa5-@P*tqjR zR{s1B0~dGqAJ=H1{5Lkg=j&N5Sjz5G^$}{L^*FfMZC`EYIOI<*nd%|>Qhvy%_n#4J z(7aT`C(T6-O-MgC+Zy5|!rLRxAU@R5*_LB#yHeAtHgaH>((EHP_H&-Y`DZqb{RX;a1G-nlQiE>E zg1*y8_Twkz?!F>`=4rvN1WBpQEIRgCxltBG`f2p<3v%a-Pd_d~EgGyIZNMK?6PzNV z;)s$aB@3mzJ&a|?|E`W;7hrm;auq8Vn74gy=8hLAy<8ezBojLD9b#uTwXm=_>!(ea zLpMluUiH6Cy$w}2hOTJSoV7%AaUJ`-c<}NPhi~o)F1I=%PxaYwi z#G#Z#NoAB`8gD|tUzx$dW+AY`>kCPXx~Nt+tTylvRzmq&LMRhSLMs(lgWm+>ryL43uXS1#WNR~;!nPf6 zGIgV=Tq_wbxObm`3VWRz^3QO6At+YLR%p>1YckcKQ9h{TF{1aL{}Awo~ zAWVV=N1&wFXc=>mO<4%6C@PZ`+(9rI_ky(#{v{V~(r$In3wm1`a=FT+F{%cCq@Jg* z4DB*7P5u6T0I2OadU{B?hQG)2;U*?001&q1v3dO$G3!A3m-RY=83${5tDc6Ug7qX? zJynGYlj+fXZ6qp{-Ei0 zkkqUD`lw7s@V9dGoejxr;wC-)(kjpTC_gsvru*G1RE03Apa0sKun$U@sY^Net2#>X z9hj;VeNhTZ+W1brV|CPZR7iWnz3I95P*(0rm5R4bpZ?&SwNh5@{i!vm;@VDsklmu$8p!FknfEkM`77G=NC94 zxa1)E;LTv&P7GzYGaRg*++eAP1-Kk|D(iPR)F6_eJU)BGfZ3>JoHb#r=UmE1{7=Ye z2W>XRtH`mHo82lD;49Y(DU|BIF|rHp4^1kxXcz0hni65NGaN?C;kwtoazi-IEg1$I$Vk$YUWwr7-FmCI>000 z{Y>q!SYPCMx&oZ4IZPLpJnzdLVDC#NT8{-YG{Sbq@1bF>t%6ShBKPB;9?Nj@6lV5zxF7+?_A-_758V}}hc2lO z|8;sDug|9*6IAjtN=j93xM~3b!t?X<;rKqMD{WYBKZMQKT2Zlp=63ma-F0a}O^Q&u zvd#hgq%80SJLv5uNH732&jRj-=-swur20bN)seWb6NA1VNAt#D6q6Hva)oZ86Pi(# zH+dFCE#;~X>1CTc6t-7ntX%4RZ;dNNid4F`8>^Fbn3#xp^LsUL_qc0oW8{n3-b_Aa zt<|taf9P$pYP1nYU)SB!<>>KW5h4zkt)E$L5A-xIUZ8yjFng3t1b_RfCQa%F=z{=v z1}`jq)uu!Wkqi1x7aAah^xm|R|DWN>?0c}wS1IC2x3=|zAN*p_hXzO4hW!+flh`ON!wDR1r<(j4=?xSt^bq`KsdTOS+ zm%CLuro6C1{ol~>)CkaB_qumNP!|yCVWUh4$yAMGI-W0YOI#kjzj3*2upCJ7%hcl~ z>-+#2`;F*#i@dAxM|QU(Z0a@xQ;6I07g}J-9xu4qo(g+trNUny&hD=Gp1$YeO7_+( zo67&1YuMsZ45xSPrO!{QD}TmfSEcul9=5$y`BKrsE$0>fP)A9S_bZ+GW?SlBu(Um#B5_@Sk-mJuP72#GXy%{fDXU?` zOS*JlWCLFWf`6%GomZFP9+|jBn6BjeRql)zq=Rd+#rRZaGf%26SBygq z5DGrnq%JR##4VAlQi?rkJ|DuQ-;Wizn;-C$jbfKC%~X<=m6a`d zEIQnnJ!yJ9o%bCts!2OKp8RPqFZh%l%MNL7kb&;NZ0hyZ-IOjJ1)MjaPVYxAp%zUi z=E+e@Ro+parTe_l0^gz3jkAI`iV}i)MgpMw>Z;4e58EJ6e(=X^m`**i|Gmv3Rlr>y zA(1p0@J`*k&pgO|!WiZKD=;Ewg~r=)CAZ#J`kWO>Vf=`dQGY(XgyL0e75m0#__4?K zpFj9lND=dRA(^JRRIr_qOUoD(Q0+{vF-Dbi~rH+(i zYKCqe>9em6l=8f$ivrRiOqA3{$-1XK{Oroi%yOe{8nLrcuc zQgn0sO*My%rRnfqgam7YH=Z}XRt-`t1)H8yMZNp9tVzl-TJTn~yq9nnyA+m|61=Vm z>HS=5aH=LSowmV24#S$>u|+K4xDQS8u|JIr3oHC&Wkm~yLZNtX-l);|W0fyne!d*$ znaq`?0Cuf4;{GR39V zO6GTgN=iBdq~BzXsYJj8N`>al_v$^WyZhZ7n`v08Ka2_OBuraT4k5TxxS=p6fd0V3 z7^%=qO;5#@os#6sx>*+TQbGKQpP?0EL_!_*RaI5rQwDYfJRd0vVrBYW4A?K$e_^g}oyhRA6ayG85`H%ZQ&ZC$#s^H5 z5+w?835kJ$0q0XOj2fi$Qc`99;!$GS zGS~7Nh7|yjeQq57$T|o*5z=XPW6a`r7q81P)~t>0gl-$CpXpD>jr_U$fx*!Zo7Cix zEIV^9k}0+|c`aF(Krmz{+zZ+-Y{k%tJQsV<8;@W0$c<}a%^+H_$@{jdEF&Ys)<4ZM zt3NMq31ArAj^>g87_N_fph6-NAPD5O24%(f;y~QS5im`t9hBmg9gaslb#B8HB~7C; zgyUS>aC_$|4?)(89NV$_mUS=iBq~=j01G^cT)~ zHTjg=lT!e2VM{)Tl>i|ToXV`N2d_y!D)K7Gv-COCUyX_Jw|}!qzCUCND^|t9T8Iw( zEh-wr5rrQCy;DiS%(=o=CaF`pGqSl_Mxo2a3X7ikZ$VMyfd_=cy|gR1js*2l6stf8 zifjhM5Q*)EDkxxmGxT^H9UUD<#xsJ!Kx~!c|FOF5CZoJwU!#|d^3BF{etr4ACT?=q z#m|T2E)A0K(x8Rt=(T6*S$VZ#+mwvhVUAS%=AVHN8t@SwD!Gp?p&tx2ePa<_yILmroEt(28Sp5252GKV=Aj!rQHYG#)2&(Fjs7{7-_s5Z%&)c&4? zv`dpI{iAs)3Nu4Kl>$m}+1fo;H-87hSws>7$*xy~t?VNQ&Yg7v9J317uOAo#oVE`| z&3yoSo>TxJ#U;PX;R?f+G>F}d#wzCd5POGC+9~IpVWG|>>hH)^szDs%YM`gHbGRA? zU&Lwgl+uD7>fTtNulU>OMLy#!(`ifB=;XBy4?;&LR(*`1q>PwC3eXJ$q6b;}EQ`~5 zP#l0gUv4{IHI>(|Cgj=YBiBe2zk6+d;W>MJ-rC+?w?Tb1W<9(}^e}3dpESFW1iH_% z%7LNDSod$}*5;A3(08iLe#KN^8t=%DKK)lIQ~^fNuTYDis8$#@<guAh)H1wf)%(3x{KL^~doUF!&QzMlqKcWkNr2YjyPM!l;3`90Dl#aU&0qIu!bJAF zH&KAhcSg4`q%wlPtpRq~R?>I+8(xB7xNB>Fx(oWMvc6R{i_z_ppbmeBTEoW1HiC|e zOV7@pV8XG7p~;*%7}eOwi-JWW3IyPP@v&~)uGMAad1C!o_<=hXa&!(%w|FZcC z?rt5RThMFv9$2+)`$O?d0qai>0%osoB@~t?#7QK_A8If00vH2-dYo=J&#i9rrKteD zWzWON>@T((O3GfH21g33Z0}FgAf;~xF441Pw$g+Y-4Qs?weDS#g^@Q$@+!MG1_?n6 zMeg}8d6ji9c_TNWnrBxx2h8ZMf~tLV;150O^lfQvR*@pVYHPi3=B>&jf)-l6Yum~+ z{R#_@fL@i`Ph>+sBy#U^_iaf`e}$R2W%2|8rRJYxV{utiRoiZ85d#t~IM)U8Yfe$W zF0g#4FS>tN&ff$e?}1y~ArbJfFZv3xRHDe?cehQIllskz*VNPmgn{d7R-pM{sdA#| zpO^TdvClUr{g(b5{Z6%3tgH&tTml9MB|M{7FpX=yL*LhnHU=zeLlK(92gA-4bYflm`s zA+#{}XS(p>`c?Cw;LY=r`Vc`!(PQJXIRgKU5#>uiKnd@ccyvPBL=sD@9$QDFW$!=o~G-Bd&`LIrL~VL zT=eE2T)Wn!Bkvi>8F@td+gKVmHn_C%{W-aN%@r$;G&SlQIOF~LP|o9(oIiVwfuo-maC!Vw>P*80_ zP$)}F=3u!YJV=I>Jn9q}R3OFlXORUv4>mMQ%(mc4P-mh1Lz(!%#f6R%`f+icBPlVl z6EbTcVQtNzUZPZKfXZV($5DQuRq)fih0$YPxT@dpP=`Gv-d$W)j{CHB#qi${Ouj$| z2=)JDDtBD&^X!YQo$J{dZJ+}t1>H|cFp_NAd{_{N3Qyi>&c^h6Hjl6v&d9jJi)iIc zIc}RaRaSox46G(d8Z+V0A#rF01lVIC;jZ&;ToDb*b+=*2tcr??iIW0^jQHl*JWQ<( zO%L&S8f2uM6B~aG#-P}_+!=Y#%sg~g@P<6bUGU}GL-rC*U#x~GM4hHihM98e>?t75 zgY88tYipH}=63@|lgjf8(R(MKa@t1pei1uyE=LHGr~Uk|o|R2na%SzSLi4`(z_y@; zcK?<(n(3OJ8~ITYR02z6c7vLrX#Cz<&r>55>{f&zCG5D=>w}@Ui3hrlJ9F?d*WTPnSu70F~jFH_%{l4)!=%f+rzrmd10} zXjiKsd+~&PeD(|3*>|`=OAkEs)Q;-^mf=cVKBO1h&u+V;_$H}Da;xdh+%EE@{FB}i@d7XAYzDoTDVSeua5>N1-P}Ie-aAdgWk(NXqYC++!c=zt}N9^(? zR_Cw3`~_k^o}%>8V5Re#BJkj}E`>$W`mr60azL`O|4#j2DlBGR6u?qX+kO)x*NDVP zVO;fBgKI8?5i>K=H1Bk#bPcD7dlY1`I}MP|oRD zFYtf7`IjS-6G;`&xDjaI7f*3hX@Uw6CZ%6So2J9emAKfQJa0>_(Fv1Fr# zN#Pu5aV>IvXa7^(bvputz#H#hX9$vTg%r+nAF^9Xr#-P&`Y^I zKpriRTD%YLZAv9|YipJ}iTjLic`U@9bAH^gnpQ5jkg#_F_yU|aqUjg3#UXuzghMu~ zG|@Ld6SLq|qlLx0z-7y&@6C&cKW#=}+ppGtX?+qT8u`(e;%u(N=}UPYjk^21Q;e)z zj&pU7Ni^1`-+*ZJH@&sF<7XhUl5`!T>WWeDMPY_d_UdBLt>Eh{;>zEvE&Z~LDb#cy zE$8$bos!ZW$h-$Pn=#r*<4Ls z`d;;E)fzXc7E(-FvdOs_Kl%D-N*XlNMeq;PWDp1S%C|vewTLO#1HsPK)s<(FZEicV zu<+g2?F z@m(y7R1ElQ^Dfu1FqHk@eQnm)udG)>n{NCWH;0etrHP4n&gAr(&(gX~i7RmYrc7jU z-5M8}(fi#EMBP#eny;F)YaiAW*31;hJaVe2{;D)KmlNGk6l2feTst^mV`5@12pG4Q zsurL;KU^08bVeKr=SIImYf1{i!Bm-fH4GUJ;2$=E1)R)*Ii?5U&`1$pYF3$x_`r?FgeZ}SXfoIp*Ofwbv)E$f{9k)jlIeo+{rh)Ip7WjIA6DVXJptAW zzZqBKUYcsMCv4gtKN}3Cg-K6QGr@?Q&(94!DYm;wG4pw`fx}73Hr<@~ac}%5JCNOYj^-B>Qlb2uTK=ZNDwLnv0mTEc% zhU>AR5I^8FVQ;)yu#<0VXXUe2wPn$5O$U^2olomXc)B9-ywoBh9o*&Bh(;)sYQdL~ z;$wai)H}lT`u!md^$XJl69?3naykRvGxnI~zMymcrY@Vzj9^#8=1|F=%?!IL)Ag=! ztuZGZy$A2vB?^&2-)=0)I?qM5|u?>qOt&Q zkL?q*Sn+#Ty#E^J7lz{UAJPuP2NUQFvtm>r)y5pfP8o$i0vh-a==fh+C^u{MWRhwZ zRck*B6q{NbD`<{la=Jy71WR+I@{oPBo3Za$WnXFQ&3{_w#R)~hHv5kQ6$P9Q&DmpL zwk(IN^?1nph~@sQP@i^Oeq3yDFkjQuPR`E85sfT-=Yc2|X!KJEjp8uu4OWW(uNFd1 zPEf0-CRvQ;WF_AjYXr}A1V(AbgMEovqly3rRY-5rJgUoTb{jbD@!mh zesju&yw9qoTZ5(9{ZPu*mZ@RI=P=lK;fY2-PGG5iZs88 zGFB#5iFk3If%xiU-*5U{U*advHC(s2HZcAu3e6tx#V|UW{>r?sXAa~2Ah~4;ie|g< z6$bGc#U5tqhz~OfFqIO`14Kwo2f$Wr0S>fTI>;n>se@G%?O7zPEAw7Gee%Z4uLDt<( z#ks#PIv`5<@k1VPV9eFo5d$s}sjMY!Q!iC~&ZpwdsZlp?PO%hN2#k%cqnb$aoeBqc zgfxdD$s6FJ{DUWA-1iRbRHyuBTtZF`BSG*Y>RL=U1&6l%C1y)Q1ewp5gv*=%{QR87 zs4;PuJEd5{lB#P*~G!fhO%jm?*VMGfOfl~H9Vr+kU;>z|u2^X(rWgM4&siHP)ai;}YC#s~dkiVgneHG5S zU#n%0j*41qI9~-Z^v^p54%mo|*lOnZFV?>y^4V%5qUaOT&w7-!sNLjs<#?}Y#(;sO zsPP9vn7nb(%s)Tc^}C{(BuZOs#{oe*_Ytk$X0lfpOBy7cGis|s6c}HByfDs&(Pi69 z#D-bzz@3NU-u*`%nKm(Jc&?1AX|ICI>$X5yoXQ!_;#~!MJx5{;`bT_UnW1L z>!~bI$BvK$sxuY;9t6iQ(fo!#>DxM9jyZ?CH}zBSWx!BzRO8~%m=$@cs2!0*0=LqY zNcMDPco7B0oCqmd0LB__>#?A*a+F_Q2P7dcOA?N*)VLUUG_ zbReoz^hJ-2Hr=3?@y;=1OO~B)@8&oUyN3>DG8{?T>Lq5`f>V=;CS(1#g!d2#_M0m>)PwZ~$_#d3Ii6Pv$@H00J|wXS=4 zLcyw}rbuq^q$s`+Q;96dmqXMAU+Cm-?Ed$$SJ$O!FA*M|ByrjhZVTj1u7 z8FlSdS8Dh~JyM!(=Vy(B`vz#iSb?_`Yn=gJJ<@&rpTHdgN38sis6u~17QM!^nuH>q z*lW@ZX>E0=IP{$ybc7&jKKrSK5BzKT@>Ky8J$@bAU@l?={pd3@JRRU40MexaJ1mp` z3JF1YwAbjYq05&1UK6m)|6d^oLfee2$7Oup3J_9;quZ3gjGTovQd577qr?D^OCchNEQ73{M){_4$TRx|8hsq@U2DZkkY)AUJ@FQ>Ujp={vts@ViknGap9X z8xs9jWZ@Uw_>u@+OWs`VeofhQq6@IP^5lOIs7U7bJr)+%MlISat^ zCi(UvrJ@VbHrbzrB1rN6@(!45bhe`X`#cO)m<+FKHUcz?Ns~V%pRz*BT<~z7iWggO zuGBf-8@AUd%iMQKowE#vHFXTG5#n;-FFEeyBzI z(LQRE_j;OpsB>#33*Ij}x-|<|LESVtHhOB?q(2L{l&DS}!alqETeE@hZFi(z5uF+H zsC)onMC^5ozgz{1E| zdq3d?JdWnXfQI1DJ9HOc2v8+Tx}hx*m24)fl*ssQM5s7$|3!PgSd2tFkie>bhv(*WJN>& zIUpFLbyJZ2ZaMt`-LsU4Pz=P!jbwj~Xt$wD?w;vwrmZ!suOObEu=ShzKa=eM=FTsh zm#=D|k6aTWyrNl~2gxnIsPdBt8Wy1l)4Al+5hLA+Y|7odBgh!B{x2cthR-oJmZ^Iu z2+4up;$_2SHHK|?=-$jBOzz*kRd8cRk+7KqjvZ@KQj+G$+c7)64bRJ+VLqBiAJ{Kue-cY+MJrM@?&lE*%8nQ$lXMM97)7#&_9wTu;=L*h&NviXM{{mzE@g2 zD-O9o=}m#hQO~OthvX$_%q<~3MKQh}n(%5Gaw^@_J>(~h9oJ5~Ra7IKdaqG{20WQ= zT3?vL_8|YpFIP0X_#Li`Odt%gF_EjMyTOZ&g<5&aj45b}mixdIz&ZBf7|fjv1MYnH zxs2U*J7!x@&~8F{`kop@In`7WTn31XcW-Z5*Ft%Af#UmY;tnP z8})p2z-o;yBL_Jmr$~m=a&xBy^Q_3F*@}t<2AD!ZC4YE2o1Jp;wmaz4DW!Mzx_uUx zs}f-Q0|z8t$|gs={l(h3c1MW7tB$zjovns1dY{H(E1vq+$vdp^4~X4(IfXCps3JT* zCq0zVnS=dz4_!2dd_WTF>9E%X?O=%FEn)D!*Asg2#h*5&Lh+{;^MWu9z~U3okt6km z6dv$WIppm6^qSe)VB3t&>+lww>SnsyDhvC) z3JL#cO!Pf%%mPf@fWNx&?gIW_y6~5?D72eDG>U?=#F{ORB;Mc4Smdv3eWqb9A}auX z4vPL)sWR!9{g5#MxoD6K??+N#OvC4BE#=Y3t?Rs+Sw!+HIt<7q{mYncy~fv^^LjAq zfjrX7{fXBIQkmRZl`2Xt3fwi|#qud?tbV*XrX|7pnv>&nw0?Fbqg)h$x5m`xY^Evy zBydJbm$ARYkexSste{Y{CO9oO`o}HEQG-r>_LIV*b0ctgXu%d1M|tnZ=%zS`4S`3n z{*$B4d*)Im{Jd9y!8g-K6}a?FP7B_R>W8cJSgVY|V*(pWZV7|#RiHCAgrOARi>9bJ z!XziCMPgO#$tKOQ+f#Xz8(va2_(NNmQZF;Ku(kvtbW=+?ox@bTsIjE>)9}ShU{jPJ zJ=pN-wXg2O-%IcX6-f3xQ$H;#4wS_G9QZqGNw)&g4KUbgrEUIHa*3twjkB5LtyHGs z_aWbiXGem*aDPRuVQ1}EKkbn2xEv`6ct+6(NLMo$#*{$u*Y#Juh2a*{6lXom8p-3UqY9x) zytK+A&oGJ(Pq^t+Sz8xP`eCCTX^Ko}5sp-akZ*&OOl<#H?LW-h9z<8I{&jtJ{2Z=s zLrDAMz|8rt^-4Z6fM`j7XtSE^-`JltUtF4y-6-?KwV{<4>Wl8qr^EBqk`Cn1TYd#RLeFa~hRHG4n_b z7{*l9A%)c%=C%nmoxQ#uZGWb9o&!XR2zvn{h1bmQ=DaWNyI@vk*8G+Aayrkde@+Xf zcgT~PSJ)Axt^|N`Q)v) zd%7~p#d1mpuEr#x6piGec~#wZ96Hbl7yc)_A?4 z0DuMoq6c5Q<83weYuE@dSjLyc`<_)MCg23HbjH?y(y~5~=e$D9R>@J3P*7yhu=BxA zzWGHqmkKy^WMrb4(^YC&F_NKvsg6IY@O|O~R^KLXHb~UfDiNgGy)B@#JgaWc2^I~) zQ#aetpH9P=+P#U$aIW&W4kRgVJ>(ujW!Q^>Y|r)aB;XblfOs+OsQnacd2 z&=_Nx8JJUimh{yOo%{CfTVxa-rBOd$TxZzCk3DEBe)5SLu8fw01sq)iJND%7yb_GR z-$`IyX@k_6a1Bq2B*j%)($};?mAjV}7%TJ~mi7kg8o4=rrF@Mfn^>OXYNOr(y8dzh zflZK$tIM9>j--W^jWFZ}QwstvMS zkk|t=u)Aj&3gBN?=Zb;3^&&I@`c{#0j&SOFT7>z-vrzGZQOLvB2UC*U*YQj2%T}QW z)BbejvhS^#`D+NU)Dz)~f}ehr0)yrRhgBg_92<7{od+}d!d5wc;I@T&lRMv2gp~e- z0{~pgj|yReXatxKOUZA6NxMTzUq#S9J(xa9COyDdzU41Lc7cGKE*Z#MyQMWM$|9=Y z45SMN|A21Mg5JId^HH*?WWN})f+e8uw4mgkIU-MIh=4T}wXK*?P+W3L3^$Tl8H(`W z9rmBKd@xrmOduI#K17GKMa}xXzwt~n`50G4H8!wNa{qjVG$$0E}VF-g?n4)E}H+hjl|8%MS z{jY}(4{u6_H9WvV(jPXxZp>5Q?TLH7eWrOhEU6 zPj9h`f(coz81-Qdwje7&e7!vJ_i7Ur~b%CYmr0r`+V_G2bA4<@Z1` ztmk5tQ8byakVTC?1L9dylQZF?0nOUAzjx+3>(s1E2L?5&1pZ!8AQ{Y6P@%5ORr3@({d?>S|^=^1Wu1 zyPENjLxt6n-M#M59ZQ$T1w#+sNmUZKy7$wyov8Q=y}RIi z5A`ue`@*GJYaK3IC`6dtcB)N76djGx3>huBel3O>X2R%ZF!=|_OuO#afe{J{z?GyM z{=MOUGQq}l;Zl)!Nh*KaBOGmQZ7sdDl$3||7g&|8yf23v(7Qez=4IqC%UlSB*fY`T z?X$}l#Nh=E|KPa<>;_|i=}51^(ZT9R&pLYP9q*@jGG#ALOF=$JXQy2?Jw1IW{VK`e zVoqGHqXr4VrAT;~^hArYaklq*kDR9?KTR^{brxOe+bPw$!u|ALVD;$=O!Z5LhN@YO z$ntpisZrNy>1l-qo7|k)gTFZ_6;88NhT&QI0OD%8UGY_Q{QyNiMuV*Sl&#skB_f)^ zkjUfJ4WIk0P&WkBeFd`~D$B{bfJ1hUD` zsU}J~_sM+A4~5c2^&^8PW@?Y;v-^!z%0>PWCkcUn$wLF&n57#nL*xbI{sLx;5vsr^ zQ~GR*B1)jp?1+}2B)v~l+h4p46aO>yHQz(?KOS-Bb5J6GrEALu&9j_y{6kZ6)DsK% zo*#Xe(K5H*>iGeD5fpWl9BQ5rrJzc)(?bVp`bUe$Y!4{w$lv_*x=ybNl8Ar*jbXMB z8TUMqNd?rM1%FIHQ+hkiv&7q!PUEPp57+x7>H7NHqnBb|RAPqd9i>+7!B z*ws-^x|tSdd|2khCRzG80GXzFNt9~9iO{*0fH2j!3Ky^GY9-b&d}uj{WlP){HG>+IMCl(IiwANB>lJ{r5Y zx*i|Z-lTt?+?D`jNm2YZ*HF*)B4^`XkA`KE2 z;;Z1l?BGoClvc8ws@Aas0=f)!U8PRBak+e%dFTXlrc*ktQHigh@a! z+U5U(Iu5Ph?q+=rf8Zz!71>J#^*fc>sLxG)Gj>OILG^Titwi>2;Zku3yO@d8NUInd7bwn8?`ryeLaj!2C)A< zp|g@trpB=trCZwIZ_0go(vdL4P27k;R~D{fX_J>oa$org zR(*5=`{!Bd;sLJy$j=LVf^w6MMuI89X7+3a;Fq+aB&$7u8(^@+^auV+qZZMDB zK>WuO+$aTOTuw`<%L+L*xIdbF{;g@R{+09+)i>s3uJooy&=UvoQ;@k_x|2;=tKVI( zlcJSjy7_pT=IZSiB_-yrzcfmbZ)gkh4(cY2%X{6<*R_ZZxToEG_@o$#@CJ^VOfT9J zx+J~Vztth|PR9JjybTQZtI$3vTEpDCcLEPtgmfu#@Ww*KeX{fyPUQkl6^Se|9F(yb zEhGQb*H=IO>%VmF1Zlf8CaSsUKz0yj`z4XGTuG(m4Q(^9ZZ=O3SP}vbJ=c$Tb#`Vs z+Iu04lgrEzEVnk>saVWJAyV4gK=rv*J$asv!_2=btC(lj%qll5ZC{VdN2$R{Rfm}j zS73?#g|EXZ~cHuzNwRMcd>Csw+BBM>1jB_6*#mGF$& ztx*ZkP?Bf;9hG6WyU{*PjFGv=Gi4)B;tE(JR-JQRXVX}(U*4Enw$a?nu}~I_yT7*U9N>wSXiv&$6CT<8U=>?O z=8jdzvk91!g=6=ZRRo9l9Z_KNZIf5Sgh~N!iG_Uj5K-N0d|J;ebR0X`4TVYXQqrOP!$j>77_5?$%w7Xa37B6@K`V~sh zgY!_HGpo-$oiZCrk0n`P^A^!NK$w_CJl19|O!&J}E`f$Fu2F7SsMMw{g*XVP7Z8qYV`8|G@Hd69qTNJblt!woK$k&<0hu7|GIO#+4?h0=#upE}EyJg`?7B`_Idk^Br1@~+#ai>- zZwT@^EL{m<7ao4EKysDl?FLE4UF<&^%H#Wat87t0m539E?oXALsE_jgj-M_Oq$uwSp)EW1OzJ9;Utc=Ym#S*?S9$qd}B75Y?w#IC< zn!Mu!V^V^-V@AwyI6QHx#0hO_o_q%PvH2GU0yG%ZEH7%H20i{-jB1iD%3C%|chyI1({N!hl(3vR{z2??@M; zP2$b4gm;rGE1*%Y0C7;kN2QVz+ zQ5J3zz(WJ0nYrS0#Z}h6=ejc-yT!zINxETSz}r8rY7LZ`YHxO|5+qowIhHIbh3w@2 z+wmVKqzs&F@HN=3kwGK5Se1wkJNs?(NX(-qq~q>~(SFE?8ZxOgTz}6N`mN04ZjCKx zrrt~h`>h*HxNmWnrF$qUUlf#*KHD{dG+=aY*_>s5vaoZR# zVF{}JRzaL2pt@}~;|^C19_;S}R@WZj+$6WFCK)+$p2ww1=7YG}Rusl}$DSh5ZYT_= zq4#_GZ4&T}0gF|g)>buXy)OW5!WWrT;K_>1y!j~x*ev@ooot3q4yL8IQ1fN9tNz^b z5>)H{_pObeJ+js;hd+LiDsNGxhV{Ik8J1K_VNXgvDpeyRi9Venklu(_W}M}I)V88@ zPYq?Ph9NcflRcZ>BP%31GxPLXw7)R0{Xi!o8V3S2QQyB)ad0$$0hPm62HI9Frbktr z&+Bs*-3I6S2qli~>DH`y_BM-NmaJ;hmm)diUKz=cy9p;4ET*Y}qzz>MOUC>c@&Jw) z%LMv^&SF0=Ce|84OXP5G&jzBX77!ReH>u+CP!#;9wSOc^>m=foyY(TE^Ydo|ik>pS zPSW4O4m(MIWGT(;+2|38&tIv*5|mXa)20^7+d*)7fNXCJ{PWvSp5%(z{W(aSW}C(b9LjUOcD8) zgP4m%GR%uIcTn1$#NDkO>v|#JVeDNp zG$=Y;;F*$IN9Ht&BR-(B5a%pvJOw zlk}?dyxWt6^dkQDvxPTYk^3sYk!#fr>291i|b+FUXve^PfiaH zN#BWAQ4p>Oe}W+Mh3)?B%{ecbcxYRdjRN8E&2Nf!G=<;O;ZWcWI6w_DRyLDpG$+;xz_YiP;S5-h=eW5xmQ{g7}xj#+#5xrTq*+WC+q9*5K= z)46PKg};41#mD31Q;Wa*54r1uC+BjQd^K^cHV_W#HuI8!8p#Vy-ef~F;L1vbtrZrG4vgX^@dpt2fdv-ghCJu6GOwyVV_%khPHfhY8 zK>&6^oxVm=C5@}+YfITzZ9;ekT+hP=7}kEdcoM}IqZjw=LONc{^(NX4Utu=A_D}`} z2Una`P#ResyTi5~N(;t$B})vI9fVjM{-If|RB|%eZ;`fvE{?rFt+v{tabNvbIbL1; zp+;mvTaei$mEzo5zw$?5OYO&fB7k2o-B!PTce9{-_ z<)IkOzhog&pZq2g;RgBU5BytX^)nb3STpiA?7qT>0Bu2xRE>T7{ICYtV=aR5gw0*K zY%sZm?K5r8`>X}4HQdNdC?5_Thc=+-oR!s*j_Sp!tq4DZtbzQ%cn8|*B<0ja;Mq7K zv=BgLi5p3%eekjNO&O%V%83Eg~LQ&Z^K zlu?O*G~!s z5&?@wJ$8An6|vk7rk-~$!h*yX{7KGR%3!)G-gU|`8s_%MWNay!)qat8V}B?2Kfz!W&E@u0VKkcl3!Jm?#HVw3_gz+C_XrCcX3~} z85t+{)vV>Rr?N(UGHkcmQ#G$zO>@W zk;AHTV*wIV|c;k~bgnc4AHKW~aL7m<6*vYsWzb9kqVZ^pNWm@l|5&!=iao+!6s zZFjBjz;2{%9r(qoiCF`s}1)<)n zk1Vx0L+5}j-kvCX>K-j#{eY>us~zEy7ygSWyo6D5#>uWlK$zKZUFKatW~bj|McNg5 zl`R|rs^P@mf(fQCD7b`31G~#a$=Ew~K$lQT3(b?rY^FtBwVW2bbloKoZl4Zw{~l|$ zt4}-mq2P2na2th(fsKn>xEkTrz4yoMEL zr&OfNWj?VgLppxII-yr?><0*SA*g3ZvB>-3_PCT6WU3X6GZ>7T-uPq9 z?-RtBXrl&E(QJGSNIZ8JKp)u@*bN!6hbM*R!=`Nx-g?LEScrp|A-qyAKkz2*KldlZ+<_OdP!>kT1=qSj41hRxr3VlHBL?(O5-gmme<;5!1pD4G8EWSRG{h z+!0i;#?|EjA^6)IyMai4a}in5=0v*A7Tn)Yfvh1p|HZ9_Hz48<%WFmC{Oz+JKDUGZ zB;vJvOjJ}az$83ZFoe=HF`;<(y9eoeIS4jWO8eZFDwLybw^A%Yfjll(!y1aVh9(H+ z8mO(=MdIc=JvUU&E4_ww0&x;Q*g>*qbndiH+TnT6%oEa+U}Gziim#AMFY373N(<18 zRcu-k7pMS_j>_>wx=75E8Deny2-$35Qj*1f5YZ4XWKIfI1)jFv5O3hDJ)@`jdnmrm zk5l(bkB9%TjM*K8b#1N|=`<5-OB&P#WMv;t6Y`xof9>w9im)+Yjl6jq8`)U@)u>qE zA?XKdd}KM1{ByaHf$c2+H+zx`{b%HN>Q3?}{k|vmtZnx?Sj_;Hd1}$7)ax9Hu}KczTw4vsa{#&}P;ou_ zPzknY4hsVjgthy4G6g}T>wgCv&M7`p4nGUgo6T4ItiOE&UEOR+)3H?L8LH!V#$!Wy zWu2`n&rG!csQ9?U!kUU2GE1ezZeQ!$ztb0|T$jE)fG6XR^-;nlI9Iyi*}BOv@!N16 zbx~pwv4EGnK1I(bE%Tfo^Ags5e`HYEo5}TKv{d$;lwr1Xhc3rq&@|p1i28L}Sru0m zY^t}=RDb1!y>DhZce+r%#)FA@MF}438_SKDxxDGJTIv$~JRUN4@(l^XPPY*s;hxwE z-<(2d6+vX?mm+o??u*m#%#Nix(kaJh5hgVbto08Xv{6%?v>18YU_#*l!N4DooI3}$ zY`++3YKW2?Q=~~XwAgw{lo27jA)S&3JJWKiiuP%1C_HWWjrb9J+(Db6bB?yXsLh zk6p?@XI{?pe^|L0*f`ga)Eesz)oyWt0T#(o?}F_nciBZwbks0aS~Z_16u1K7I1KLIc^t+z7z)5XySL&!&R18+F7{R;F(@n7gQR^^yG!Ns^v9fpre+0l`A5rmr2=2l z+gvA=N7?9A>FDVz6_*M_%PabkVx1g#8N8L8&yBU0LJ%P~PDa;7&adu^DfA~dyK4D9 z)JYvDe$~J*IIY_HM4huO)rZj}vcIo~N8plsj!ky;3W>h?dPF`-FIK400-n7|*kJlf z9&h81fL8%a)WfMv62A{ds`vYyb#7NRzn+`lbMkkDwi(b0gA0vJ8qYo*z%0h%B^9dO z=-EVD$L}i0l=k`|hWmsC4a;bMLl9iSc^Q}pddwFkf;Uw0dsP=d9F%6!Rf=1%Q^l2E z>xFKQ2wMIP#@e%l5wXq&h@&Wo8g_z@^H>M|ML%e5R2?w5M=hlyI;>+>6h4Tn^nAWQ zZs`oJiVV5B*IxLGIm`vnV{v>1zg+r#u$QAyi&kc_Bm8|N5UA1*(Gg2n!WPvC(-^82 zG@4=cOym_>x1!n{>R4jDYkx0{*Hcwh-C63_nS+pJpZ@K68RtaLwyMdisj3QDrshB3 zmiI-1#dv$6H#*}8gb!;Bt&UY0`kd}{W78^vKmd|0xOO=d;S>2J>Jgf?pa~~??aVxn zon#2&6X)#vSJ{YJR46s3e?wLB@(@?*JYOm!X1hXEhi7d!lFB04aHeRg zi%3l5=!UK6u)ds-eLTSdWQmCVeKR6XdR_!O9o#RFcCh)a5a>}G5s2Swz6 z+iOQpC=C7bqe59+s3K1dKiQ-q-t)=v)(ZF6H9QE9p1*A~k_F;so)Kkhw zeC=y@3FrzM65`sYlcJ5Qw#mGyTBivXh&2uY7E?OII?8R&ZFX5RpXG z7Edb5HoyLJIlpYWbZI6zdvr3kknVsk_oUo1v>n2)-|_8TAb^&R@$vu^CkFjh=jxXn zI&Nvl$$Abk2T#B56Yx}-P-lF>2VoCAVu%M_W8{Z*OV1W%j-PR&+e{?45|>{q z85G?0orz5zS1IM|!E&nFV0PB{f(9_)8Q;I{bZ#PYPCH@*p@Hn2d5D1+wse0u3d1|Q zTdRE*a9Zm(lwLx~O3ILHxYr z?5+J4Lvi7*uK1q09AEYy z+Z$OTY7;+nAGo9A^`N)S!}T1(gG~e$ztUxid=BzOkR3$!f4q&^lM`~}>6Smex(viv zFDeKZ=#WUT6%ASg8AmLgr7kZo&-jhz#{RbG4S~^aw!--La2^BPAZsj`kb1wID1eOZ z;U3K#O0w@WN+*E`R6zFcd@t@&BCPGw_MlDinq*2D7^;1aUrwv)l&dru0khpIg%M2l@E(v$kC;2Ti}`{P zg!yv~rF#o4ef+>OfR411h*TNbibcTrI-3uoGWuuu)?Yl9d3MuAdwIkk(?@BRCVQz^Vr+(N|50_W`-3c4f3$>~99V(sK-zuZ{Iv{USV)g> zK+iinI}}KX_FKq39p1O~Uk4EZ7W9!PBSdSiVbXdrfp!{9`Z(|j6CuwRoD<{0(_P6v!4S<)6K5> z6$7RB=(cwU-rx`L*xdXgD=P*7W?!Mx3?^XQDKa=rj#no@*ZPL>i^?g{4?}rOL6sLJ zqNAR`^TWdmrMlj6g%m{=*{_8^KM6Lt9%IZ) z>ul+Y(@hqitRLV0;>~utb=VDOWECAdyYIQYr3ABKdh@Q7>vfBo8`8ibA^g034LsoV zo*98!kk*l$tF|KzBFtw=_AdMfUE0mM<(9D2-`qXhF92tL7glg5zhx13W(_huZqNlm z0t`}kjga++{ILdL)+guVBLq-1PHp-RFbKg12ZuYke~MHxvO}w2QN+m6uk_MNuoiUm z{R=AHp6}=|;nllY+lVG5UZetkbBEIZDHGSYd0|4T_=4DLM$~J85p0ROBt=)N z^=;=WGQrDCaz{#hH;Qb|1)q-zqjya-f*FCbezmAFPRAr@7AhD7 ztn|eZm0RK5iHU#+_fpl)RRW*}N!oKICV4DgniKOFLgh}NzD z&YNfgUC;@d3fol;_Rd&(p8SC4zD5;llffA`c5xwQY|p=lA@a;2^)bdta?DM*TXQ~# zPpjw&oblC>k7X=own!R`Ency*@P1jY8Y0Y7;Dl+&D?)LpwJEoNvD!Y3*Rjzlrp_Uf zy_{qGBaX}Xf@o1;kGaP(a=q5bzetrd-Ye-3oDp&kWw=S*IkJWb5%LfFR>e@&Avg_| zH3j+r7;bfQC zH&S00`0-D^P4qNVRgpRO$HFA#&{kVVxZ&P2@6fH^yx+fN<+;ynd1Va6aNYqWp-f^e z#9YvC4fmH@WB_|1YQrQ~R3t-h1U$Xu?p&uPUPQ-`Jh0f-%3Q{#Ojjb9qlSmQ-s~y#URT-LjoEzs8 zL$je4EYePCxQ+3SJ)M=4Jv#gS?@4(3jmcxOd;F)kJC+*N-GM9G6MPHO1Ng zx&}h!;LRM32(JZnf2(Jn=B+t?Qc`COFN(kW&PB_8txfs;4`o*07oYFj*c;H8!~iNM zD>>nqlgrY{tC;&&JSNj<3NLTOuve@&I~i8u5JWdwRT{JK`B{N`e}((Ou84dYE5SMWVeO;9D*k=jUAru*h zQr`Jg;)G(O4amk`o*5=PN`4ce9n(12;1km$R)Wi~Pjg{)-Pk=v$Pf|YoR>5r1C9`y zk8(`B=V#79<-n<|AxIWXL&?v-ro@{DnHTsOn}Quq_Qn&rf6+(2^fG9dd*SH*6U%0H z_L*fl%~!a79+Jb02%FY`9O3vv`BUzmBZs}qRt*gzHZyqO7;VQ~4w;6_2lz~e5AfWF zDACp<3JbvlP`{2tq^z)NWiPpn_~DfVZxWu@OR=q8+1p-N90R}AFxzHW#TQHCNKPLG z?Ojs}O?f*u(++y@~qiUGxZ`K3VjdbVN$1FCKfZDbC?C8`_1+!`SzQyuQw! zwOj8=fqJ0CFNZj_?s}L1I2J*m3!D#%f(XagF*C6KMP^rI(5JNEKXh8zIrs-saJQ#t zKaz`=VLzMRs@^x5T>0t%{usJimEy>b!F8Q_5*CmfL6v9kQM;PNd;G#wtorz8R??<# zJGNA!^qD|A;xq!P zn8XLM#WtgUDBr_Zt#fFX(tdJcCw{OY2&4+fgm5+fK(GYn+s%Bl_SUxvYe~|}&SR>N zX6rdcPbysl4DaltLs~0r{3zetr>?}?n^N>hq}bP0*jd`vtGA5#kRsxaeCf2G>~ug5 z$f)4;$~u<)C&Vf8GC+(7nV(lDGNU)f!Nr9HF`ccq-u-KhQic+o`~;+IUAP^!9XA(q z)+w3@mklJ|$?ltnvCJTmSJn@_NZO#ozKTMch)QqQiW&ECt{ zwJ}t%i1*fA)I=5WA*=y8IMBlVw7kK)QxtkcVDpluUV-|H8%3w6#y4T&W@-^P#CIZnj zkMI;NtmcHoM3oAo0S{(Fn6+Qddw}~t2yjq^H@|e!WN%##1K5j%EWOAlI?d~`XRdo} z1V8xg-MsXC4||Of1}3JVN{uQI2*8J+Tr}4qEwHhF+aEU5tZF_r6F|u1*FmTn95bPk z`K}0x_~JHSJWV5DhO zZ$|{0=Y%3H16F;97@9{p0*-JDDen1HHqrSUyAikUunFj^Ntc$aL7iY#ViFRP*-id6 z`q7JDdvU53^__|V=dy}JEpIQR$)5C%!N1+_D>bg3{Q##CLw2`i0zAs)0ih2s+==-- zcV9NdJ_@6m#$N?ZXd}znWxV~Uzm&mujIB$5%gS0J9)A-EIatKe{x$0tIQ%wc`VvKB z2^%jn&9f#wNy7ObCk2>Jn!QR?*VrfDID zTwjZ|sO$qLa-tvxFf6qWM2Z<6<)^uLJ_N?Z6b%o-qGJV;&EF`K5FLJ7_Szgrcy12F zQIls&a1rY6`S5Y>2vk07(Rp}q?;EKmtAguSw-B!pLEE(2j1k~&T9?~PQ}|Mn-*luO zzU5tgIY~*F6S@3&pn8vUU4ZTh5!B!KS=|1H06`5$56;w-}3lg@mzlE-n{+dArzc~*Z3G@QPU#gG$2oXtxfc+dGzYwNfPLk zZ#=p=qI<{2SYZS+0wQZ-TAHTy4~RATmH(*wq0=AQ*4DD+`I%i7RhnPrR8>#j0748X z2x+?Fmftv9dS%1_q}^!s=ep8V;a6s^l#(&yL#6`94JX9I_Qn)qmJY()Uhh(4ffv!O zvTY{2Pi{#dd*B}OKLQ4DpgE~kokb~DP8x=UF5z^Ysrtqg_2tQrVh$d!JpS*eMbr7T zb~I!*sMAU#bZA(Kz7l51*YAduUfrUK3x0=v^yjXCF#@E=P>@vP`*`smw)3Lv<$|6+ z{6$_57`E!|&olv*nSzZC(|)Z*_%J}QPv~R@qdAsgT=ffikUVHSjVbJ){=d*)^X1I- zV?hyOwkqRz$kLglwswZ5l6%Yu{di+iez8JraFSV62<9L5aV?+AUj$O_;ec}%N|ufZ zp%RV-MEx0WYJIT{xx_HSMzA^m+e4xEXU3)*bfYH0`Q|NuzfI18i;{_S!QpyNOdEM` z#4$6KSGqX@;U3e4&{IZv%gCSDvMRS+n(xv0Q}6K9_C*n#@@8H!z?})?R=&Nu{#O9B zlD#9p^7gnDKQSS{X396%;yF!9)oK+&Bb8bwCx)B_^<}dS3z&e~czLyd8NZ*@=Vhy& z?vr8)up=|~E5(~d{jq6OkZ32u>6ez=hrq~`^YF~uDfmpAIVZ!k03Du#aJPR^__HZ! z3{p{ifGOT^GXi-95r1(osqPL^=MWVt#x0Pz>S%Uvw9PUeI=GO;DJ?vnw`lf*9wIm!YYKPhG8=f8) z>|9xsPeL=vd?v3(AfdDU<#*3WJLPH46gWd54|BuSVkvrtpHUVGva6zz;P2cFIm4L0<|LAuqe_+CI@sCpKd6SYC7yvWFuCZSzgNs zeuNusu)|C2ZV*eeP`}|~yEcqJ^Go9Y7&r5w7q2`Ejm$}B%M^?=Ow`$!lese*xAtOk zym4`|;to3(Y#RH+Vbm9GKA-s%DD?4q%Z0CQuGbyVi6TJT@Nl`M<#R6Ybc#(Do-QQ- z1p6G*Zk4P^1iX|(XK3%_7b8c|!*vp&GiklHU_)jg!sY7Nl-$)N0%&G(#_P{q!_}li z%)A~G_>?1#(1(U$;X}~SStj#@Vn~vVkaR=kt&VeE{C3v5g9^6|IO~FVoWug?Fa`ob&Z3L? z*kTNMi!R!D(&=%#^>bNc?-0--SJIp*U2FREz+K&)4H#Z16kg~z9XWS8bs)RaLLS() zcl!<|`Rvf%8~L)iQ^rS(@bZPZm*Y_W6)ia_>2Iu2?%#%CQU+@L)w6-clsekIN<+b` z`J(vkBi^Qlug?_>a{np$7BCFo>EY*&t-o`K)xc{$xxF7*YaTRXiZc5c(*&N{A11wH zVbcUyptG-GHM4!!S7Q_J4F|h0`2LmGlL?!=s6HiupKWJ*x%YsTnV6uu()1DHU}i=G z47UuPWXlpc^mah|N$>7p%%3(_%a^Y?`Op4BJmTz#CrY4Aigc?_>db43F0pYU6(Ei< zLhsbccVSxft#t-aEzC@gewlo^${~g_Bd3b8X|sh$EIl)gmNiG2{d1jZXR#V|-%eIM+a zZ5CwnBjeUUZtS2EF7?|h6FQdzCFmkMy3rK9{BRC!?s}5<~(!(HGkJ zJ%aM8g0=GZ`|NzTj4Y9cS@r^0JFei_%1VVgTeu%vTotIDf@Q^$D_N9%RR)Gnx!rWH^V{q7gE06`A4ySI0aq&k}SS^$NpfUU9z01F zSIl1lyY{ij=#XRcGKgMwH8a~(8U7-m_I3E@JF6PU0x8#;h$L-?Axx@tlvU`B`UA9FtL7+hVRJalg+9`pjvWMWi$xu6h<@O) z2sD6#toQX+*eQ?@qSmS3BluTTM#Vy%?!J!kE zc*tQ21+slMwU92Q4`dN`)~8X~I6p6W|9DmPdg}I2px(>Gjv#)`Ji|>(g(b5g7|n7d zIz=pTMHFuV02yYE+fBWz&DNp7f@GB(bJtv6%X)wUX3P1D)n~^#CBr{bvQ6uvOlsV! zFb}Tg_2~|9B|*Y8zXV4%`Qk;PuHaO#I$)h|ZSq19ER?YP+>G*H(ZaneBLxOjPOq~J z>j7d(g5fyO8u3H_eR}h7VXN!o-FMxoALStozQBH?9p^vK%&pLo$Y{D5K}FJSK{yJs z#YhW$k3OA`r~zGOvL1fBB-ApzM%xQUnNnsVe5?k<(x`xK%Cr3)q6 zQiI5xZ6GZ%eRevAr3X%Q^nxWsgU=DkvX&u&`~<2VRyO;MCCC@z6($l7RB zv5c;ysf5Y?-h5w)eFm;mT%oT%Tts?pVLd_%xe zJYlzw@Zy}Yn8^5FdM92XrX9eyKi=vV22)bHmoGs^E2SU}+VY`QiY=y7EC$eZsfxd! zmwE1)9OK(zHY>T);Z5zqYVF1pRDNTOT|+!Ekc1V~R0=|Xx?%|eVoH zY8YTq%DcI>CsjvjNu-npdLwH^TwEIcS;g#}ot;a%T|XxyMdy+zPFoQKk>&dwbOnJu zrf68~#B^>}2RjyWm5Y^4x<+M!bl?|k@nDGAmB^EYp_CEs5cKsBoS1~9^+gSEJ;dS0h_i}GW50gW#HnNA0^PM93*#pZZDUr6ceqB*obi>F1Z&Yk9Xy> zYIx7{EwvR>VkgbDtB;4$!JmlEX_w;9Y581VZ|3VS601Qob8@z*OSOUP1_AuAgQL)z z;)J39y#}$M&pd1*I`hx9SRm~3<_TG%QuyhQOTzYyx&#yXidyJ|7gVtU8T})8U5%Ntjn8@ks~6exIfa+NqbEnN?YfmG;biy(mV_P9hp)k zp1yD;ke?zBzD$pd)N^OsmpK4MO%1_R1GYdUfJQ{J@w;%mc_1SeasI_~5fJ?_3qEqi z@89~q*C~7G?d_34QLtuQ@H;k&Q8?)#zjvAuJpGMrfCQ*o>>Rb@7bN1eQ7^Go{Bcl) zr}0@XVdXh%4D6tuw3nqM>3;Kb>1^fInV_X>|_x>#X3a)A}5;BK@L9%a^G^1_Z*1 z6HCJrT2uAsGN}=+&6zY^ll_K1w-N6~c1R^Nf1tPU;jp2`MO>IjpWea$alsAkhJow7c5=9tyjx~XZN83PX{oYr@#bLs9K}@cU@e2yblc;% zeNaWt0gqw`Ne&mWnoIY--;n@igvmfBLT2D;@M5S%Ta%QK^gYGY<9fIfYE8^Fcxs@}fL9_YR3147}*zyM(MozMdKj{ks*{uFjq?;e0Q z4rXMWM2)hUA>{X{e(PPWjLQSfLeTgzCA~4vge!=db^urSEOrRs;C3-$SY)D z*KAq=SX_07CW^1dwT7x{h-fJ63YqcR6slgQPfO=@)gPb#ihj{*>@Cy%-=B{tQs3*f z2CFM+KK?fUjI&QQ`44z7J3ISd)mP9f(Qh30`$U$(>DWn9}Q|@+7GfvO|pE!^W^}b&;S4* zoR=2}9OXr4dc_(Kqy(FrBW=yiRl*~~0)nyr0Dxxhja(y}zfBb1cwZu`$pACc4E(Ab zLA|=sqo<`y&8lRsUe{}1HxK%lQ_*H1RCff30M&@;eCRmeCX_SI^AR^gHr`TPb=~LC=-H;bZnhVxgg;s8uj!q# zv{l5``~o@(#D7R_MFeVJ6k8k{ISMyema@Kra!IG9-*Mc%d7DximhIO^UZ=8w?*z8z?861c9qu zkI(NhBEFq8`61W#vFIRD^x^LRx+liUtWCDy;SsE{Jfo>d-~#ci-=!F`ii2tiaFVuA z)M!G}9&Z1(G0y1c@aI(4-P3>FqpIiplnW~%5SlkPmmgUrAO_SJeZ z!Bd{?n0F@dL@?aOEeZh8QUC3Hv1CLH4+5iY9V~&f`~m>M)9a!8`* zNQW+#0f`V*RYjwSoZe&zJ3G|JASfQ9WZxw&nf-7<Ze;*Ij3273@ExEU7L;;Lwrllr-unrTXAO%71|Vw8+8 zKvD0H3NVd*V!rvm;NNJuf2Y3DZR~U;byK9|R}MI8R0CQ##~c!$Oz8I9(Gg%?D(L8* zUd*B=1~`Rh7KijZFgDv73&2?=J-+(Oso`ut82?FZLPzVQmWI0*kP*6u0ezrRPSXW3 zQm`t|FY?N8RPyed+7WM#R%m-wkMW?R414r@_kiLpJeM9H*D`Oxw~oP7p8rMfyFFCt zzVNkWBg7s@5@9|-%v-@^U;AmLWWTaQ;CW;{v*T!Tyzh8#!DFq^N|>hBMs;ljCW;Ce zATFk*Ys)Fua-Yjv5$mIICjQE5M`3p&E&|Lk##o9A$T4_~!Q9a}q zC5yZ_I8w^>m4abzT}@qF9jL2HSAbDkiccII&)^mr>Uf5%Hah2Nn}_N*T%HqztMMf> z-zhXpdwOkHT#qOh1Q{;QK9C$i&$bn|p%PAot)wZn&Rw=c@=A8Y1aI8sGAxSPsyE{R z)<0t!3WE2KKb=G)gyoH}C9HZ8SPLr9JIr|*>biS%#8r$q(=S0e@8OzZtNl5B=1u!3|87Pa-f9dZD(2PS?@ zyPU^<-zrX*(qH(>b%r!|;;pOi&0sn58!K=K*}LdiQ}|8erF^l1vP!t@-s~o4qwQ~0 zUcFmZhC-giUO>x8hTk8BFJs2PGP~VHRufkt*YphIx;odb+%pO%KGL-^Uf!f?I~S0|GmysSPF)d0_KvJVZ26N53;1p1GacbK-aTg~>JlSqqX`)%febSms za;A?HQ>{11HO2nFgeLAIw$`M4PBkt1`c=Deo12!Guv5O13Bpz5r?(>Ju^lQD zc(F5HOE=3gU7nLNbk`!7*~wP6yCSQPDR1^BDEg|`HTF-Xl0GgW&NfKUi-B{-c2uk2 z2a{MWc~tE$7yK?5UbbyS5jj!pT|l*xMzGf8#jWoe)$#J>;zq?2S<7&#Zk)tW^Tyjy zlQ`wak8Hk=Pn}~LMrmJCAoq4W@nED47;VdrIUa1sM`G0fn0I_QA#1llZkWxn#6jNN!aDb%DbFHhW^b4O=llJ?;_HMxek8^60=?_~mEYLb L($S*M>{`;laxc~L diff --git a/examples/messaging/jms-websocket-se/src/main/resources/WEB/img/frank.png b/examples/messaging/jms-websocket-se/src/main/resources/WEB/img/frank.png deleted file mode 100644 index 51a13d8db8bc02ad1613da3b809cff394462a77a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10516 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 - - - - - - - Helidon Reactive Messaging - - - - - - - - -
      -
      -
      - -
      -
      Send
      -
      -
      -
      -
      -
      REST call /rest/messages/send/{msg}
      -
      -
      -
      Messages received from Jms over websocket
      -
      -
      -
      -
      -
      -            
      -        
      -
      -
      - - - - - \ No newline at end of file diff --git a/examples/messaging/jms-websocket-se/src/main/resources/WEB/main.css b/examples/messaging/jms-websocket-se/src/main/resources/WEB/main.css deleted file mode 100644 index 358c7857297..00000000000 --- a/examples/messaging/jms-websocket-se/src/main/resources/WEB/main.css +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2020, 2021 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. - */ - -#root { - background-color: #36ABF2; - font-family: Roboto,sans-serif; - color: #fff; - position: absolute; - overflow-x: hidden; - -ms-overflow-style: none; /* Internet Explorer 10+ */ - scrollbar-width: none; /* Firefox */ - top: 0; - left: 0; - width: 100%; - height: 100%; -} -#root::-webkit-scrollbar { - display: none; /* Safari and Chrome */ -} - -#helidon { - width: 509px; - height: 273px; - position: relative; - left: -509px; - z-index: 4; - background: url('img/frank.png'); -} - -#rest-tip { - position: relative; - top: -80px; - left: 160px; -} - -#rest-tip-arrow { - width: 205px; - height: 304px; - z-index: 4; - top: -20px; - background: url('img/arrow-1.png'); -} -#rest-tip-label { - position: absolute; - white-space: nowrap; - font-size: 18px; - font-weight: bold; - z-index: 4; - left: -60px; -} - -#sse-tip { - position: absolute; - overflow: hidden; - display: flex; - width: auto; - height: auto; - top: 5%; - right: 10%; - z-index: 0; -} - -#sse-tip-arrow { - position: relative; - top: -30px; - width: 296px; - height: 262px; - z-index: 4; - background: url('img/arrow-2.png'); -} -#sse-tip-label { - position: relative; - white-space: nowrap; - font-size: 18px; - font-weight: bold; - z-index: 4; -} - -#producer { - float: left; - position: relative; - width: 300px; - height: 100%; - margin: 50px; - padding: 10px; - z-index: 99; -} - -#msgBox { - position: absolute; - width: 300px; - top: 25%; - right: 3%; - height: 100%; - margin: 50px; - padding: 10px; - z-index: 20; -} - -#input { - width: 210px; - height: 22px; - top: 58px; - left: 30px; - background-color: white; - border-radius: 10px; - border-style: solid; - border-color: white; - position: absolute; - z-index: 10; -} - -#inputCloud { - position: relative; - width: 310px; - height: 150px; - background: url('img/cloud.png'); -} - -#msg { - background-color: #D2EBFC; - color: #1A9BF4; - border-radius: 10px; - width: 300px; - height: 50px; - margin: 5px; - display: flex; - padding-left: 10px; - justify-content: center; - align-items: center; - z-index: 99; -} - -#submit { - font-weight: bold; - background-color: aqua; - color: #1A9BF4; - border-radius: 12px; - width: 100px; - height: 30px; - display: flex; - justify-content: center; - align-items: center; - margin: 5px; - cursor: pointer; -} - -#snippet { - position: absolute; - top: 15%; - left: 30%; - width: 40%; - z-index: 5; -} - -.hljs { - border-radius: 10px; - font-size: 12px; -} diff --git a/examples/messaging/jms-websocket-se/src/main/resources/application.yaml b/examples/messaging/jms-websocket-se/src/main/resources/application.yaml deleted file mode 100644 index 28596dd1af4..00000000000 --- a/examples/messaging/jms-websocket-se/src/main/resources/application.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2020 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. -# - -app: - jms: - url: tcp://127.0.0.1:61616 - destination: se-example-queue-1 - -server: - port: 7001 - host: 0.0.0.0 - static: - classpath: - location: /WEB - welcome: index.html diff --git a/examples/messaging/jms-websocket-se/src/main/resources/logging.properties b/examples/messaging/jms-websocket-se/src/main/resources/logging.properties deleted file mode 100644 index 361bf5f6cbc..00000000000 --- a/examples/messaging/jms-websocket-se/src/main/resources/logging.properties +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright (c) 2020, 2024 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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 diff --git a/examples/messaging/kafka-websocket-mp/README.md b/examples/messaging/kafka-websocket-mp/README.md deleted file mode 100644 index 75269ca5ca0..00000000000 --- a/examples/messaging/kafka-websocket-mp/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# Helidon MP Reactive Messaging with Kafka Example - -## Prerequisites -* Docker -* Java 21+ -* [Kafka bootstrap server](../README.md) running on `localhost:9092` - -## Build & Run -```shell -#1. -mvn clean package -#2. -java -jar target/kafka-websocket-mp.jar -``` -3. Visit http://localhost:7001 \ No newline at end of file diff --git a/examples/messaging/kafka-websocket-mp/pom.xml b/examples/messaging/kafka-websocket-mp/pom.xml deleted file mode 100644 index 603896f410c..00000000000 --- a/examples/messaging/kafka-websocket-mp/pom.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.messaging.mp - kafka-websocket-mp - 1.0-SNAPSHOT - Helidon Examples Messaging Kafka WebSocket MP - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.microprofile.messaging - helidon-microprofile-messaging - - - io.helidon.messaging.kafka - helidon-messaging-kafka - - - io.helidon.microprofile.websocket - helidon-microprofile-websocket - - - io.smallrye - jandex - runtime - true - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/messaging/kafka-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/MsgProcessingBean.java b/examples/messaging/kafka-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/MsgProcessingBean.java deleted file mode 100644 index 989feea8c19..00000000000 --- a/examples/messaging/kafka-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/MsgProcessingBean.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2020, 2021 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.messaging.mp; - -import java.util.concurrent.SubmissionPublisher; - -import io.helidon.common.reactive.Multi; - -import jakarta.enterprise.context.ApplicationScoped; -import org.eclipse.microprofile.reactive.messaging.Incoming; -import org.eclipse.microprofile.reactive.messaging.Message; -import org.eclipse.microprofile.reactive.messaging.Outgoing; -import org.eclipse.microprofile.reactive.streams.operators.ProcessorBuilder; -import org.eclipse.microprofile.reactive.streams.operators.ReactiveStreams; -import org.reactivestreams.FlowAdapters; -import org.reactivestreams.Publisher; - -/** - * Bean for message processing. - */ -@ApplicationScoped -public class MsgProcessingBean { - - private final SubmissionPublisher emitter = new SubmissionPublisher<>(); - private final SubmissionPublisher broadCaster = new SubmissionPublisher<>(); - - /** - * Create a publisher for the emitter. - * - * @return A Publisher from the emitter - */ - @Outgoing("multiplyVariants") - public Publisher preparePublisher() { - // Create new publisher for emitting to by this::process - return ReactiveStreams - .fromPublisher(FlowAdapters.toPublisher(Multi.create(emitter))) - .buildRs(); - } - - /** - * Returns a builder for a processor that maps a string into three variants. - * - * @return ProcessorBuilder - */ - @Incoming("multiplyVariants") - @Outgoing("toKafka") - public ProcessorBuilder> multiply() { - // Multiply to 3 variants of same message - return ReactiveStreams.builder() - .flatMap(o -> - ReactiveStreams.of( - // upper case variant - o.toUpperCase(), - // repeat twice variant - o.repeat(2), - // reverse chars 'tnairav' - new StringBuilder(o).reverse().toString()) - ).map(Message::of); - } - - /** - * Broadcasts an event. - * - * @param msg Message to broadcast - */ - @Incoming("fromKafka") - public void broadcast(String msg) { - // Broadcast to all subscribers - broadCaster.submit(msg); - } - - /** - * Subscribe new Multi to broadcasting publisher. - * - * @return new Multi subscribed to broadcaster - */ - public Multi subscribeMulti() { - return Multi.create(broadCaster); - } - - /** - * Emit a message. - * - * @param msg message to emit - */ - public void process(final String msg) { - emitter.submit(msg); - } -} diff --git a/examples/messaging/kafka-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/SendingResource.java b/examples/messaging/kafka-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/SendingResource.java deleted file mode 100644 index 71630c3a38d..00000000000 --- a/examples/messaging/kafka-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/SendingResource.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2020, 2021 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.messaging.mp; - -import jakarta.enterprise.context.RequestScoped; -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; - -/** - * Expose send method for publishing to messaging. - */ -@Path("rest/messages") -@RequestScoped -public class SendingResource { - private final MsgProcessingBean msgBean; - - /** - * Constructor injection of field values. - * - * @param msgBean Messaging example bean - */ - @Inject - public SendingResource(MsgProcessingBean msgBean) { - this.msgBean = msgBean; - } - - - /** - * Send message through Messaging to Kafka. - * - * @param msg message to process - */ - @Path("/send/{msg}") - @GET - @Produces(MediaType.APPLICATION_JSON) - public void getSend(@PathParam("msg") String msg) { - msgBean.process(msg); - } -} diff --git a/examples/messaging/kafka-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/WebSocketEndpoint.java b/examples/messaging/kafka-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/WebSocketEndpoint.java deleted file mode 100644 index 757f450b5f6..00000000000 --- a/examples/messaging/kafka-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/WebSocketEndpoint.java +++ /dev/null @@ -1,95 +0,0 @@ - -/* - * Copyright (c) 2020, 2021 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.messaging.mp; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.helidon.common.reactive.Single; - -import jakarta.inject.Inject; -import jakarta.websocket.CloseReason; -import jakarta.websocket.EndpointConfig; -import jakarta.websocket.OnClose; -import jakarta.websocket.OnOpen; -import jakarta.websocket.Session; -import jakarta.websocket.server.ServerEndpoint; - -/** - * Register all WebSocket connection as subscribers - * of broadcasting {@link java.util.concurrent.SubmissionPublisher} - * in the {@link MsgProcessingBean}. - *

      - * When connection is closed, cancel subscription and remove reference. - */ -@ServerEndpoint("/ws/messages") -public class WebSocketEndpoint { - - private static final Logger LOGGER = Logger.getLogger(WebSocketEndpoint.class.getName()); - - private final Map> subscriberRegister = new HashMap<>(); - - @Inject - private MsgProcessingBean msgProcessingBean; - - /** - * On WebSocket session is opened. - * - * @param session web socket session - * @param endpointConfig endpoint config - */ - @OnOpen - public void onOpen(Session session, EndpointConfig endpointConfig) { - System.out.println("New WebSocket client connected with session " + session.getId()); - - Single single = msgProcessingBean.subscribeMulti() - // Watch for errors coming from upstream - .onError(throwable -> LOGGER.log(Level.SEVERE, "Upstream error!", throwable)) - // Send every item coming from upstream over web socket - .forEach(s -> sendTextMessage(session, s)); - - //Save forEach single promise for later cancellation - subscriberRegister.put(session.getId(), single); - } - - /** - * When WebSocket session is closed. - * - * @param session web socket session - * @param closeReason web socket close reason - */ - @OnClose - public void onClose(final Session session, final CloseReason closeReason) { - LOGGER.info("Closing session " + session.getId()); - // Properly unsubscribe from SubmissionPublisher - Optional.ofNullable(subscriberRegister.remove(session.getId())) - .ifPresent(Single::cancel); - } - - private void sendTextMessage(Session session, String msg) { - try { - session.getBasicRemote().sendText(msg); - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Message sending over WebSocket failed", e); - } - } -} diff --git a/examples/messaging/kafka-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/package-info.java b/examples/messaging/kafka-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/package-info.java deleted file mode 100644 index 3fee934038f..00000000000 --- a/examples/messaging/kafka-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020, 2021 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. - */ - -/** - * Helidon MP Reactive Messaging with Kafka Example. - */ -package io.helidon.examples.messaging.mp; diff --git a/examples/messaging/kafka-websocket-mp/src/main/resources/META-INF/beans.xml b/examples/messaging/kafka-websocket-mp/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 4a5ec955fb7..00000000000 --- a/examples/messaging/kafka-websocket-mp/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/messaging/kafka-websocket-mp/src/main/resources/META-INF/microprofile-config.properties b/examples/messaging/kafka-websocket-mp/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 1c88f678e12..00000000000 --- a/examples/messaging/kafka-websocket-mp/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,36 +0,0 @@ -# -# Copyright (c) 2020 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=7001 -server.host=0.0.0.0 -server.static.classpath.location=/WEB -server.static.classpath.welcome=index.html - -# Configure channel fromKafka to ask Kafka connector for publisher -mp.messaging.incoming.fromKafka.connector=helidon-kafka -mp.messaging.incoming.fromKafka.enable.auto.commit=true -mp.messaging.incoming.fromKafka.group.id=websocket-mp-example-1 - -# Configure channel toKafka to ask Kafka connector for subscriber -mp.messaging.outgoing.toKafka.connector=helidon-kafka - -# Connector config properties are common to all channels -mp.messaging.connector.helidon-kafka.bootstrap.servers=localhost:9092 -mp.messaging.connector.helidon-kafka.topic=messaging-test-topic-1 -mp.messaging.connector.helidon-kafka.key.deserializer=org.apache.kafka.common.serialization.StringDeserializer -mp.messaging.connector.helidon-kafka.value.deserializer=org.apache.kafka.common.serialization.StringDeserializer -mp.messaging.connector.helidon-kafka.key.serializer=org.apache.kafka.common.serialization.StringSerializer -mp.messaging.connector.helidon-kafka.value.serializer=org.apache.kafka.common.serialization.StringSerializer diff --git a/examples/messaging/kafka-websocket-mp/src/main/resources/WEB/favicon.ico b/examples/messaging/kafka-websocket-mp/src/main/resources/WEB/favicon.ico deleted file mode 100644 index d91659fdb53c934af789e9b93e2d92c679f975d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1230 zcmV;<1Tp)GP)*8l(j8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H11WQRoK~z|Uy_Z{T6lE00e`jX8mqMWtT1?w51zW;RQDQ<{=()Hdzz zw!1sW2fMg*x83dr`hWW7ob&&FCuhEyofXfTJ#V90OB%YTYYw|#iqKDJj0GMwK@Y%Lzb*2G_bGtSTx(vr7!0A-X zHY!8QihhFz^yc-LWJMPj_pR+MShshrgzV#hCzVZx^mxsF+CGF=0g7G^6xo&($5mbY zRU=mL$Bvzg{1cN{v^qesy}_f-QEV5Pufbps^#z|0E2J zJyz}e*Pm0dHv$96aq&}Dc-QIF?TMP7ook+Zwz{~M`igKuIKUO}#-k`(0XumEaWYG1 zxfWQ4oQVxi%aZoGC63%h^D_sdv4n5{-+}5+6kbjPjv=^9XFKynxC}7K!Hw-JUA7_Q z+)_8%CRg@Xzp3!vh!A7s!|gQXuF?{h>9p{@R_W@r42p)=SP6W$Hc<9MUBQV5@k8F-Od+!DwicL++HXZpB zC>zZl3`18KfDYSW!={DO8_kV6_NXo&tq5jB2G*gRNnRbVz7S`AxlUu1Z1memKcl6e@BcFUqZIhcm4*geIb?&ONqhXK8GBAj}^Zx{0VTbCj)n4Q0uQ@WOY3GbL<) z4%~OMZLl?FTJv)B(5m^FE27uGo$Wf+`qR~JkfcvhC=~8aSTtitV5uFpcLBN4SYEbu za$=_8ztA~&bCdx!9ntmCFVD8LwzMq*%w*sp*>U&0XotVnRy}M8lMAL;Cjh;-Fyq)9 zPsW1|6E#io=VeCs3=S+l1BWlMtO?K|y>C7OHf>NCK>gxNa_|4+r0 z&65W0&@qMkW5V{hzyUlfzsOTVTLhUNh2P<^|1aOc>Q2L8Ezli}jT;=Gecy(kQ8oa< safbu=4pe_F$QIK3H*|aCS+%?NUyMb7$(BA=Gynhq07*qoM6N<$f|!R&8~^|S diff --git a/examples/messaging/kafka-websocket-mp/src/main/resources/WEB/img/arrow-1.png b/examples/messaging/kafka-websocket-mp/src/main/resources/WEB/img/arrow-1.png deleted file mode 100644 index bbba0aef8a6ce9efc80b64f1820f5eb38d83a209..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18222 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 L($S*M>{`;laxc~L diff --git a/examples/messaging/kafka-websocket-mp/src/main/resources/WEB/img/frank.png b/examples/messaging/kafka-websocket-mp/src/main/resources/WEB/img/frank.png deleted file mode 100644 index 51a13d8db8bc02ad1613da3b809cff394462a77a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10516 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 - - - - - - - Helidon Reactive Messaging - - - - - - - - -

      -
      -
      - -
      -
      Send
      -
      -
      -
      -
      -
      REST call /rest/messages/send/{msg}
      -
      -
      -
      Messages received from Kafka over websocket
      -
      -
      -
      -
      -
      -            
      -        
      -
      -
      - - - - - \ No newline at end of file diff --git a/examples/messaging/kafka-websocket-mp/src/main/resources/WEB/main.css b/examples/messaging/kafka-websocket-mp/src/main/resources/WEB/main.css deleted file mode 100644 index 358c7857297..00000000000 --- a/examples/messaging/kafka-websocket-mp/src/main/resources/WEB/main.css +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2020, 2021 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. - */ - -#root { - background-color: #36ABF2; - font-family: Roboto,sans-serif; - color: #fff; - position: absolute; - overflow-x: hidden; - -ms-overflow-style: none; /* Internet Explorer 10+ */ - scrollbar-width: none; /* Firefox */ - top: 0; - left: 0; - width: 100%; - height: 100%; -} -#root::-webkit-scrollbar { - display: none; /* Safari and Chrome */ -} - -#helidon { - width: 509px; - height: 273px; - position: relative; - left: -509px; - z-index: 4; - background: url('img/frank.png'); -} - -#rest-tip { - position: relative; - top: -80px; - left: 160px; -} - -#rest-tip-arrow { - width: 205px; - height: 304px; - z-index: 4; - top: -20px; - background: url('img/arrow-1.png'); -} -#rest-tip-label { - position: absolute; - white-space: nowrap; - font-size: 18px; - font-weight: bold; - z-index: 4; - left: -60px; -} - -#sse-tip { - position: absolute; - overflow: hidden; - display: flex; - width: auto; - height: auto; - top: 5%; - right: 10%; - z-index: 0; -} - -#sse-tip-arrow { - position: relative; - top: -30px; - width: 296px; - height: 262px; - z-index: 4; - background: url('img/arrow-2.png'); -} -#sse-tip-label { - position: relative; - white-space: nowrap; - font-size: 18px; - font-weight: bold; - z-index: 4; -} - -#producer { - float: left; - position: relative; - width: 300px; - height: 100%; - margin: 50px; - padding: 10px; - z-index: 99; -} - -#msgBox { - position: absolute; - width: 300px; - top: 25%; - right: 3%; - height: 100%; - margin: 50px; - padding: 10px; - z-index: 20; -} - -#input { - width: 210px; - height: 22px; - top: 58px; - left: 30px; - background-color: white; - border-radius: 10px; - border-style: solid; - border-color: white; - position: absolute; - z-index: 10; -} - -#inputCloud { - position: relative; - width: 310px; - height: 150px; - background: url('img/cloud.png'); -} - -#msg { - background-color: #D2EBFC; - color: #1A9BF4; - border-radius: 10px; - width: 300px; - height: 50px; - margin: 5px; - display: flex; - padding-left: 10px; - justify-content: center; - align-items: center; - z-index: 99; -} - -#submit { - font-weight: bold; - background-color: aqua; - color: #1A9BF4; - border-radius: 12px; - width: 100px; - height: 30px; - display: flex; - justify-content: center; - align-items: center; - margin: 5px; - cursor: pointer; -} - -#snippet { - position: absolute; - top: 15%; - left: 30%; - width: 40%; - z-index: 5; -} - -.hljs { - border-radius: 10px; - font-size: 12px; -} diff --git a/examples/messaging/kafka-websocket-mp/src/main/resources/logging.properties b/examples/messaging/kafka-websocket-mp/src/main/resources/logging.properties deleted file mode 100644 index d28553fe70d..00000000000 --- a/examples/messaging/kafka-websocket-mp/src/main/resources/logging.properties +++ /dev/null @@ -1,32 +0,0 @@ -# -# Copyright (c) 2020, 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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 - -# Kafka client has exhaustive logs -org.apache.kafka.clients.level=WARNING -org.apache.kafka.clients.consumer.ConsumerConfig.level=SEVERE -org.apache.kafka.clients.producer.ProducerConfig.level=SEVERE diff --git a/examples/messaging/kafka-websocket-se/README.md b/examples/messaging/kafka-websocket-se/README.md deleted file mode 100644 index c3e397add51..00000000000 --- a/examples/messaging/kafka-websocket-se/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Helidon Messaging with Kafka Examples - -## Prerequisites -* Java 21+ -* Docker -* [Kafka bootstrap server](../README.md) running on `localhost:9092` - -## Build & Run -```shell -#1. -mvn clean package -#2. -java -jar target/kafka-websocket-se.jar -``` -3. Visit http://localhost:7001 - diff --git a/examples/messaging/kafka-websocket-se/pom.xml b/examples/messaging/kafka-websocket-se/pom.xml deleted file mode 100644 index a55524de099..00000000000 --- a/examples/messaging/kafka-websocket-se/pom.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.messaging.se - kafka-websocket-se - 1.0-SNAPSHOT - Helidon Examples Messaging Kafka WebSocket MP - - - io.helidon.examples.messaging.se.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver - helidon-webserver-static-content - - - io.helidon.webserver - helidon-webserver-websocket - - - io.helidon.messaging - helidon-messaging - - - io.helidon.messaging.kafka - helidon-messaging-kafka - - - io.helidon.config - helidon-config-yaml - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/Main.java b/examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/Main.java deleted file mode 100644 index 57437758f07..00000000000 --- a/examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/Main.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.messaging.se; - -import io.helidon.config.Config; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.staticcontent.StaticContentService; -import io.helidon.webserver.websocket.WsRouting; - -/** - * 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 WebServer startServer() { - // load logging configuration - LogConfig.configureRuntime(); - - // By default, this will pick up application.yaml from the classpath - Config config = Config.create(); - - SendingService sendingService = new SendingService(config); - - WebServer server = - WebServer.builder() - .routing(r -> r - // register static content support (on "/") - .register(StaticContentService.builder("/WEB") - .welcomeFileName("index.html") - .build()) - // register rest endpoint for sending to Kafka - .register("/rest/messages", sendingService)) - // register WebSocket endpoint to push messages coming from Kafka to client - .addRouting(WsRouting.builder() - .endpoint("/ws/messages", new WebSocketEndpoint())) - .config(config.get("server")) - .build() - .start(); - - System.out.println("WEB server is up! http://localhost:" + server.port()); - Runtime.getRuntime().addShutdownHook(new Thread(sendingService::shutdown)); - - // Server threads are not daemon. No need to block. Just react. - return server; - } -} diff --git a/examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/SendingService.java b/examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/SendingService.java deleted file mode 100644 index 355c2ac33bb..00000000000 --- a/examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/SendingService.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.messaging.se; - -import io.helidon.config.Config; -import io.helidon.messaging.Channel; -import io.helidon.messaging.Emitter; -import io.helidon.messaging.Messaging; -import io.helidon.messaging.connectors.kafka.KafkaConnector; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; - -import org.apache.kafka.common.serialization.StringSerializer; - -class SendingService implements HttpService { - - private final Emitter emitter; - private final Messaging messaging; - - SendingService(Config config) { - - String kafkaServer = config.get("app.kafka.bootstrap.servers").asString().get(); - String topic = config.get("app.kafka.topic").asString().get(); - String compression = config.get("app.kafka.compression").asString().orElse("none"); - - // Prepare channel for connecting processor -> kafka connector with specific subscriber configuration, - // channel -> connector mapping is automatic when using KafkaConnector.configBuilder() - Channel toKafka = Channel.builder() - .subscriberConfig(KafkaConnector.configBuilder() - .bootstrapServers(kafkaServer) - .topic(topic) - .compressionType(compression) - .keySerializer(StringSerializer.class) - .valueSerializer(StringSerializer.class) - .build()) - .build(); - - // Prepare channel for connecting emitter -> processor - Channel toProcessor = Channel.create(); - - // Prepare Kafka connector, can be used by any channel - KafkaConnector kafkaConnector = KafkaConnector.create(); - - // Prepare emitter for manual publishing to channel - emitter = Emitter.create(toProcessor); - - // Transforming to upper-case before sending to kafka - messaging = Messaging.builder() - .emitter(emitter) - // Processor connect two channels together - .processor(toProcessor, toKafka, String::toUpperCase) - .connector(kafkaConnector) - .build() - .start(); - } - - /** - * A service registers itself by updating the routing rules. - * - * @param rules the routing rules. - */ - @Override - public void routing(HttpRules rules) { - // Listen for GET /example/send/{msg} - // to send it thru messaging to Kafka - rules.get("/send/{msg}", (req, res) -> { - String msg = req.path().pathParameters().get("msg"); - System.out.println("Emitting: " + msg); - emitter.send(msg); - res.send(); - }); - } - - /** - * Gracefully terminate messaging. - */ - public void shutdown() { - messaging.stop(); - } -} diff --git a/examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/WebSocketEndpoint.java b/examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/WebSocketEndpoint.java deleted file mode 100644 index edf15419c88..00000000000 --- a/examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/WebSocketEndpoint.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.messaging.se; - -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.logging.Logger; - -import io.helidon.config.Config; -import io.helidon.messaging.Channel; -import io.helidon.messaging.Messaging; -import io.helidon.messaging.connectors.kafka.KafkaConfigBuilder; -import io.helidon.messaging.connectors.kafka.KafkaConnector; -import io.helidon.websocket.WsListener; -import io.helidon.websocket.WsSession; - -import org.apache.kafka.common.serialization.StringDeserializer; - -/** - * Web socket endpoint. - */ -public class WebSocketEndpoint implements WsListener { - - private static final Logger LOGGER = Logger.getLogger(WebSocketEndpoint.class.getName()); - - private final Map messagingRegister = new HashMap<>(); - private final Config config = Config.create(); - - @Override - public void onOpen(WsSession session) { - System.out.println("Session " + session); - - String kafkaServer = config.get("app.kafka.bootstrap.servers").asString().get(); - String topic = config.get("app.kafka.topic").asString().get(); - String compression = config.get("app.kafka.compression").asString().orElse("none"); - - // Prepare channel for connecting kafka connector with specific publisher configuration -> listener, - // channel -> connector mapping is automatic when using KafkaConnector.configBuilder() - Channel fromKafka = Channel.builder() - .name("from-kafka") - .publisherConfig(KafkaConnector.configBuilder() - .bootstrapServers(kafkaServer) - .groupId("example-group-" + session) - .topic(topic) - .autoOffsetReset(KafkaConfigBuilder.AutoOffsetReset.LATEST) - .enableAutoCommit(true) - .keyDeserializer(StringDeserializer.class) - .valueDeserializer(StringDeserializer.class) - .compressionType(compression) - .build() - ) - .build(); - - // Prepare Kafka connector, can be used by any channel - KafkaConnector kafkaConnector = KafkaConnector.create(); - - Messaging messaging = Messaging.builder() - .connector(kafkaConnector) - .listener(fromKafka, payload -> { - System.out.println("Kafka says: " + payload); - // Send message received from Kafka over websocket - session.send(payload, true); - }) - .build() - .start(); - - //Save the messaging instance for proper shutdown - // when websocket connection is terminated - messagingRegister.put(session, messaging); - } - - @Override - public void onClose(WsSession session, int status, String reason) { - LOGGER.info("Closing session " + session); - // Properly stop messaging when websocket connection is terminated - Optional.ofNullable(messagingRegister.remove(session)) - .ifPresent(Messaging::stop); - } -} diff --git a/examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/package-info.java b/examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/package-info.java deleted file mode 100644 index d67f74ad03f..00000000000 --- a/examples/messaging/kafka-websocket-se/src/main/java/io/helidon/examples/messaging/se/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020, 2021 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. - */ - -/** - * Helidon SE Reactive Messaging with Kafka Example. - */ -package io.helidon.examples.messaging.se; diff --git a/examples/messaging/kafka-websocket-se/src/main/resources/WEB/favicon.ico b/examples/messaging/kafka-websocket-se/src/main/resources/WEB/favicon.ico deleted file mode 100644 index d91659fdb53c934af789e9b93e2d92c679f975d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1230 zcmV;<1Tp)GP)*8l(j8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H11WQRoK~z|Uy_Z{T6lE00e`jX8mqMWtT1?w51zW;RQDQ<{=()Hdzz zw!1sW2fMg*x83dr`hWW7ob&&FCuhEyofXfTJ#V90OB%YTYYw|#iqKDJj0GMwK@Y%Lzb*2G_bGtSTx(vr7!0A-X zHY!8QihhFz^yc-LWJMPj_pR+MShshrgzV#hCzVZx^mxsF+CGF=0g7G^6xo&($5mbY zRU=mL$Bvzg{1cN{v^qesy}_f-QEV5Pufbps^#z|0E2J zJyz}e*Pm0dHv$96aq&}Dc-QIF?TMP7ook+Zwz{~M`igKuIKUO}#-k`(0XumEaWYG1 zxfWQ4oQVxi%aZoGC63%h^D_sdv4n5{-+}5+6kbjPjv=^9XFKynxC}7K!Hw-JUA7_Q z+)_8%CRg@Xzp3!vh!A7s!|gQXuF?{h>9p{@R_W@r42p)=SP6W$Hc<9MUBQV5@k8F-Od+!DwicL++HXZpB zC>zZl3`18KfDYSW!={DO8_kV6_NXo&tq5jB2G*gRNnRbVz7S`AxlUu1Z1memKcl6e@BcFUqZIhcm4*geIb?&ONqhXK8GBAj}^Zx{0VTbCj)n4Q0uQ@WOY3GbL<) z4%~OMZLl?FTJv)B(5m^FE27uGo$Wf+`qR~JkfcvhC=~8aSTtitV5uFpcLBN4SYEbu za$=_8ztA~&bCdx!9ntmCFVD8LwzMq*%w*sp*>U&0XotVnRy}M8lMAL;Cjh;-Fyq)9 zPsW1|6E#io=VeCs3=S+l1BWlMtO?K|y>C7OHf>NCK>gxNa_|4+r0 z&65W0&@qMkW5V{hzyUlfzsOTVTLhUNh2P<^|1aOc>Q2L8Ezli}jT;=Gecy(kQ8oa< safbu=4pe_F$QIK3H*|aCS+%?NUyMb7$(BA=Gynhq07*qoM6N<$f|!R&8~^|S diff --git a/examples/messaging/kafka-websocket-se/src/main/resources/WEB/img/arrow-1.png b/examples/messaging/kafka-websocket-se/src/main/resources/WEB/img/arrow-1.png deleted file mode 100644 index bbba0aef8a6ce9efc80b64f1820f5eb38d83a209..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18222 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 L($S*M>{`;laxc~L diff --git a/examples/messaging/kafka-websocket-se/src/main/resources/WEB/img/frank.png b/examples/messaging/kafka-websocket-se/src/main/resources/WEB/img/frank.png deleted file mode 100644 index 51a13d8db8bc02ad1613da3b809cff394462a77a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10516 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 - - - - - - - Helidon Reactive Messaging - - - - - - - - -
      -
      -
      - -
      -
      Send
      -
      -
      -
      -
      -
      REST call /rest/messages/send/{msg}
      -
      -
      -
      Messages received from Kafka over websocket
      -
      -
      -
      -
      -
      -            
      -        
      -
      -
      - - - - - \ No newline at end of file diff --git a/examples/messaging/kafka-websocket-se/src/main/resources/WEB/main.css b/examples/messaging/kafka-websocket-se/src/main/resources/WEB/main.css deleted file mode 100644 index 358c7857297..00000000000 --- a/examples/messaging/kafka-websocket-se/src/main/resources/WEB/main.css +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2020, 2021 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. - */ - -#root { - background-color: #36ABF2; - font-family: Roboto,sans-serif; - color: #fff; - position: absolute; - overflow-x: hidden; - -ms-overflow-style: none; /* Internet Explorer 10+ */ - scrollbar-width: none; /* Firefox */ - top: 0; - left: 0; - width: 100%; - height: 100%; -} -#root::-webkit-scrollbar { - display: none; /* Safari and Chrome */ -} - -#helidon { - width: 509px; - height: 273px; - position: relative; - left: -509px; - z-index: 4; - background: url('img/frank.png'); -} - -#rest-tip { - position: relative; - top: -80px; - left: 160px; -} - -#rest-tip-arrow { - width: 205px; - height: 304px; - z-index: 4; - top: -20px; - background: url('img/arrow-1.png'); -} -#rest-tip-label { - position: absolute; - white-space: nowrap; - font-size: 18px; - font-weight: bold; - z-index: 4; - left: -60px; -} - -#sse-tip { - position: absolute; - overflow: hidden; - display: flex; - width: auto; - height: auto; - top: 5%; - right: 10%; - z-index: 0; -} - -#sse-tip-arrow { - position: relative; - top: -30px; - width: 296px; - height: 262px; - z-index: 4; - background: url('img/arrow-2.png'); -} -#sse-tip-label { - position: relative; - white-space: nowrap; - font-size: 18px; - font-weight: bold; - z-index: 4; -} - -#producer { - float: left; - position: relative; - width: 300px; - height: 100%; - margin: 50px; - padding: 10px; - z-index: 99; -} - -#msgBox { - position: absolute; - width: 300px; - top: 25%; - right: 3%; - height: 100%; - margin: 50px; - padding: 10px; - z-index: 20; -} - -#input { - width: 210px; - height: 22px; - top: 58px; - left: 30px; - background-color: white; - border-radius: 10px; - border-style: solid; - border-color: white; - position: absolute; - z-index: 10; -} - -#inputCloud { - position: relative; - width: 310px; - height: 150px; - background: url('img/cloud.png'); -} - -#msg { - background-color: #D2EBFC; - color: #1A9BF4; - border-radius: 10px; - width: 300px; - height: 50px; - margin: 5px; - display: flex; - padding-left: 10px; - justify-content: center; - align-items: center; - z-index: 99; -} - -#submit { - font-weight: bold; - background-color: aqua; - color: #1A9BF4; - border-radius: 12px; - width: 100px; - height: 30px; - display: flex; - justify-content: center; - align-items: center; - margin: 5px; - cursor: pointer; -} - -#snippet { - position: absolute; - top: 15%; - left: 30%; - width: 40%; - z-index: 5; -} - -.hljs { - border-radius: 10px; - font-size: 12px; -} diff --git a/examples/messaging/kafka-websocket-se/src/main/resources/application.yaml b/examples/messaging/kafka-websocket-se/src/main/resources/application.yaml deleted file mode 100644 index 949b803df73..00000000000 --- a/examples/messaging/kafka-websocket-se/src/main/resources/application.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# -# Copyright (c) 2020, 2023 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. -# - -app: - kafka: - bootstrap.servers: localhost:9092 - compression: snappy -# compression: lz4 -# compression: zstd -# compression: gzip - topic: messaging-test-topic-${app.kafka.compression}-compressed - -server: - port: 7001 - host: 0.0.0.0 - static: - classpath: - location: /WEB - welcome: index.html diff --git a/examples/messaging/kafka-websocket-se/src/main/resources/logging.properties b/examples/messaging/kafka-websocket-se/src/main/resources/logging.properties deleted file mode 100644 index 361bf5f6cbc..00000000000 --- a/examples/messaging/kafka-websocket-se/src/main/resources/logging.properties +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright (c) 2020, 2024 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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 diff --git a/examples/messaging/kafkaConsume.sh b/examples/messaging/kafkaConsume.sh deleted file mode 100755 index da1c55c6ada..00000000000 --- a/examples/messaging/kafkaConsume.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2020 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. -# - -TOPIC="messaging-test-topic-1" -SERVER="localhost:9092" -CONTAINER="helidon_kafka" - -if [ -z "$1" ]; then - echo "No argument supplied, defaulting to topic ${TOPIC}" -else - TOPIC="$1" -fi - -docker exec -it ${CONTAINER} sh -c \ -"/opt/kafka/bin/kafka-console-consumer.sh --topic ${TOPIC} --bootstrap-server ${SERVER}" diff --git a/examples/messaging/kafkaProduce.sh b/examples/messaging/kafkaProduce.sh deleted file mode 100755 index 7e7a02a8bb4..00000000000 --- a/examples/messaging/kafkaProduce.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2020 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. -# - -TOPIC="messaging-test-topic-1" -SERVER="localhost:9092" -CONTAINER="helidon_kafka" - -if [ -z "$1" ]; then - echo "No argument supplied, defaulting to topic ${TOPIC}" -else - TOPIC="$1" -fi - -docker exec -it ${CONTAINER} sh -c \ -"/opt/kafka/bin/kafka-console-producer.sh --topic ${TOPIC} --bootstrap-server ${SERVER}" diff --git a/examples/messaging/kafkaRun.sh b/examples/messaging/kafkaRun.sh deleted file mode 100755 index 4883e9dbc9f..00000000000 --- a/examples/messaging/kafkaRun.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2020 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. -# - -if [[ "$(docker images -q helidon-test-kafka 2>/dev/null)" == "" ]]; then - # helidon:test-kafka not found, build it - docker build ./docker/kafka -t helidon-test-kafka -f ./docker/kafka/Dockerfile.kafka -fi - -if [ ! "$(docker ps -q -f name=helidon_kafka)" ]; then - if [ "$(docker ps -aq -f status=exited -f name=helidon_kafka)" ]; then - # Clean up exited container - docker rm helidon_kafka - fi - # Run test Kafka in new container, stop it by pressing Ctrl+C - docker run -it \ - --rm \ - --publish 2181:2181 \ - --publish 29092:9092 \ - --publish 9092:29092 \ - --name helidon_kafka \ - helidon-test-kafka -fi diff --git a/examples/messaging/oracle-aq-websocket-mp/README.md b/examples/messaging/oracle-aq-websocket-mp/README.md deleted file mode 100644 index af31df6f51e..00000000000 --- a/examples/messaging/oracle-aq-websocket-mp/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Helidon Messaging with Oracle AQ Example - -## Prerequisites -* Java 21+ -* Docker -* [Oracle database](../README.md) running on `localhost:1521` - -## Build & Run -```shell -#1. - mvn clean package -#2. - java -jar target/aq-websocket-mp.jar -``` -3. Visit http://localhost:7001 - diff --git a/examples/messaging/oracle-aq-websocket-mp/pom.xml b/examples/messaging/oracle-aq-websocket-mp/pom.xml deleted file mode 100644 index f7d4f8f8e82..00000000000 --- a/examples/messaging/oracle-aq-websocket-mp/pom.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.messaging.aq - aq-websocket-mp - 1.0-SNAPSHOT - Helidon Examples Messaging Oracle AQ WebSocket MP - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.microprofile.messaging - helidon-microprofile-messaging - - - io.helidon.messaging.aq - helidon-messaging-aq - - - io.helidon.integrations.cdi - helidon-integrations-cdi-datasource-ucp - runtime - - - io.helidon.microprofile.websocket - helidon-microprofile-websocket - - - io.smallrye - jandex - runtime - true - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/messaging/oracle-aq-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/MsgProcessingBean.java b/examples/messaging/oracle-aq-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/MsgProcessingBean.java deleted file mode 100644 index 832f1270661..00000000000 --- a/examples/messaging/oracle-aq-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/MsgProcessingBean.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2020, 2021 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.messaging.mp; - -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.SubmissionPublisher; - -import io.helidon.common.reactive.BufferedEmittingPublisher; -import io.helidon.common.reactive.Multi; -import io.helidon.messaging.connectors.aq.AqMessage; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.jms.JMSException; -import jakarta.jms.MapMessage; -import org.eclipse.microprofile.reactive.messaging.Acknowledgment; -import org.eclipse.microprofile.reactive.messaging.Incoming; -import org.eclipse.microprofile.reactive.messaging.Outgoing; -import org.eclipse.microprofile.reactive.streams.operators.ReactiveStreams; -import org.reactivestreams.FlowAdapters; -import org.reactivestreams.Publisher; - -/** - * Bean for message processing. - */ -@ApplicationScoped -public class MsgProcessingBean { - - private final BufferedEmittingPublisher emitter = BufferedEmittingPublisher.create(); - private final SubmissionPublisher broadCaster = new SubmissionPublisher<>(); - - /** - * Create a publisher for the emitter. - * - * @return A Publisher from the emitter - */ - @Outgoing("to-queue-1") - public Publisher toFirstQueue() { - // Create new publisher for emitting to by this::process - return ReactiveStreams - .fromPublisher(FlowAdapters.toPublisher(emitter)) - .buildRs(); - } - - /** - * Example of resending message from one queue to another and logging the payload to DB in the process. - * - * @param msg received message - * @return message to be sent - */ - @Incoming("from-queue-1") - @Outgoing("to-queue-2") - //Leave commit by ack to outgoing connector - @Acknowledgment(Acknowledgment.Strategy.NONE) - public CompletionStage> betweenQueues(AqMessage msg) { - return CompletableFuture.supplyAsync(() -> { - try { - PreparedStatement statement = msg.getDbConnection() - .prepareStatement("INSERT INTO frank.message_log (message) VALUES (?)"); - statement.setString(1, msg.getPayload()); - statement.executeUpdate(); - } catch (SQLException e) { - //Gets caught by messaging engine and translated to onError signal - throw new RuntimeException("Error when saving message to log table.", e); - } - return msg; - }); - } - - /** - * Broadcasts an event. - * - * @param msg Message to broadcast - */ - @Incoming("from-queue-2") - public void fromSecondQueue(AqMessage msg) { - // Broadcast to all subscribers - broadCaster.submit(msg.getPayload()); - } - - /** - * Example of receiving a byte message. - * - * @param bytes received byte array - */ - @Incoming("from-byte-queue") - public void fromByteQueue(byte[] bytes) { - broadCaster.submit(new String(bytes)); - } - - /** - * Example of receiving a map message. - * - * @param msg received JMS MapMessage - * @throws JMSException when error arises during work with JMS message - */ - @Incoming("from-map-queue") - public void fromMapQueue(MapMessage msg) throws JMSException { - String head = msg.getString("head"); - byte[] body = msg.getBytes("body"); - String tail = msg.getString("tail"); - broadCaster.submit(String.join(" ", List.of(head, new String(body), tail))); - } - - Multi subscribeMulti() { - return Multi.create(broadCaster).log(); - } - - void process(final String msg) { - emitter.emit(msg); - } -} diff --git a/examples/messaging/oracle-aq-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/SendingResource.java b/examples/messaging/oracle-aq-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/SendingResource.java deleted file mode 100644 index 7000c579aeb..00000000000 --- a/examples/messaging/oracle-aq-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/SendingResource.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2020, 2021 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.messaging.mp; - -import jakarta.enterprise.context.RequestScoped; -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; - -/** - * Expose send method for publishing to messaging. - */ -@Path("rest/messages") -@RequestScoped -public class SendingResource { - private final MsgProcessingBean msgBean; - - /** - * Constructor injection of field values. - * - * @param msgBean Messaging example bean - */ - @Inject - public SendingResource(MsgProcessingBean msgBean) { - this.msgBean = msgBean; - } - - /** - * Send message through Messaging to JMS. - * - * @param msg message to process - */ - @Path("/send/{msg}") - @GET - @Produces(MediaType.APPLICATION_JSON) - public void getSend(@PathParam("msg") String msg) { - msgBean.process(msg); - } -} diff --git a/examples/messaging/oracle-aq-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/WebSocketEndpoint.java b/examples/messaging/oracle-aq-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/WebSocketEndpoint.java deleted file mode 100644 index 757f450b5f6..00000000000 --- a/examples/messaging/oracle-aq-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/WebSocketEndpoint.java +++ /dev/null @@ -1,95 +0,0 @@ - -/* - * Copyright (c) 2020, 2021 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.messaging.mp; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.helidon.common.reactive.Single; - -import jakarta.inject.Inject; -import jakarta.websocket.CloseReason; -import jakarta.websocket.EndpointConfig; -import jakarta.websocket.OnClose; -import jakarta.websocket.OnOpen; -import jakarta.websocket.Session; -import jakarta.websocket.server.ServerEndpoint; - -/** - * Register all WebSocket connection as subscribers - * of broadcasting {@link java.util.concurrent.SubmissionPublisher} - * in the {@link MsgProcessingBean}. - *

      - * When connection is closed, cancel subscription and remove reference. - */ -@ServerEndpoint("/ws/messages") -public class WebSocketEndpoint { - - private static final Logger LOGGER = Logger.getLogger(WebSocketEndpoint.class.getName()); - - private final Map> subscriberRegister = new HashMap<>(); - - @Inject - private MsgProcessingBean msgProcessingBean; - - /** - * On WebSocket session is opened. - * - * @param session web socket session - * @param endpointConfig endpoint config - */ - @OnOpen - public void onOpen(Session session, EndpointConfig endpointConfig) { - System.out.println("New WebSocket client connected with session " + session.getId()); - - Single single = msgProcessingBean.subscribeMulti() - // Watch for errors coming from upstream - .onError(throwable -> LOGGER.log(Level.SEVERE, "Upstream error!", throwable)) - // Send every item coming from upstream over web socket - .forEach(s -> sendTextMessage(session, s)); - - //Save forEach single promise for later cancellation - subscriberRegister.put(session.getId(), single); - } - - /** - * When WebSocket session is closed. - * - * @param session web socket session - * @param closeReason web socket close reason - */ - @OnClose - public void onClose(final Session session, final CloseReason closeReason) { - LOGGER.info("Closing session " + session.getId()); - // Properly unsubscribe from SubmissionPublisher - Optional.ofNullable(subscriberRegister.remove(session.getId())) - .ifPresent(Single::cancel); - } - - private void sendTextMessage(Session session, String msg) { - try { - session.getBasicRemote().sendText(msg); - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Message sending over WebSocket failed", e); - } - } -} diff --git a/examples/messaging/oracle-aq-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/package-info.java b/examples/messaging/oracle-aq-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/package-info.java deleted file mode 100644 index 75a27ea50bc..00000000000 --- a/examples/messaging/oracle-aq-websocket-mp/src/main/java/io/helidon/examples/messaging/mp/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ - -/* - * Copyright (c) 2020, 2021 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. - */ - -/** - * Reactive Messaging JMS example. - */ -package io.helidon.examples.messaging.mp; diff --git a/examples/messaging/oracle-aq-websocket-mp/src/main/resources/META-INF/beans.xml b/examples/messaging/oracle-aq-websocket-mp/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 4a5ec955fb7..00000000000 --- a/examples/messaging/oracle-aq-websocket-mp/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/messaging/oracle-aq-websocket-mp/src/main/resources/META-INF/microprofile-config.properties b/examples/messaging/oracle-aq-websocket-mp/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 0c719b02522..00000000000 --- a/examples/messaging/oracle-aq-websocket-mp/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,52 +0,0 @@ -# -# Copyright (c) 2020 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=7001 -server.host=0.0.0.0 -server.static.classpath.location=/WEB -server.static.classpath.welcome=index.html - -javax.sql.DataSource.aq-test-ds.connectionFactoryClassName=oracle.jdbc.pool.OracleDataSource -javax.sql.DataSource.aq-test-ds.URL=jdbc:oracle:thin:@localhost:1521:XE -javax.sql.DataSource.aq-test-ds.user=frank -javax.sql.DataSource.aq-test-ds.password=frank - -mp.messaging.connector.helidon-aq.acknowledge-mode=CLIENT_ACKNOWLEDGE -mp.messaging.connector.helidon-aq.data-source=aq-test-ds - -mp.messaging.outgoing.to-queue-1.connector=helidon-aq -mp.messaging.outgoing.to-queue-1.destination=EXAMPLE_QUEUE_1 -mp.messaging.outgoing.to-queue-1.type=queue - -mp.messaging.incoming.from-queue-1.connector=helidon-aq -mp.messaging.incoming.from-queue-1.destination=EXAMPLE_QUEUE_1 -mp.messaging.incoming.from-queue-1.type=queue - -mp.messaging.outgoing.to-queue-2.connector=helidon-aq -mp.messaging.outgoing.to-queue-2.destination=EXAMPLE_QUEUE_2 -mp.messaging.outgoing.to-queue-2.type=queue - -mp.messaging.incoming.from-queue-2.connector=helidon-aq -mp.messaging.incoming.from-queue-2.destination=EXAMPLE_QUEUE_2 -mp.messaging.incoming.from-queue-2.type=queue - -mp.messaging.incoming.from-byte-queue.connector=helidon-aq -mp.messaging.incoming.from-byte-queue.destination=example_queue_bytes -mp.messaging.incoming.from-byte-queue.type=queue - -mp.messaging.incoming.from-map-queue.connector=helidon-aq -mp.messaging.incoming.from-map-queue.destination=example_queue_map -mp.messaging.incoming.from-map-queue.type=queue diff --git a/examples/messaging/oracle-aq-websocket-mp/src/main/resources/WEB/favicon.ico b/examples/messaging/oracle-aq-websocket-mp/src/main/resources/WEB/favicon.ico deleted file mode 100644 index d91659fdb53c934af789e9b93e2d92c679f975d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1230 zcmV;<1Tp)GP)*8l(j8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H11WQRoK~z|Uy_Z{T6lE00e`jX8mqMWtT1?w51zW;RQDQ<{=()Hdzz zw!1sW2fMg*x83dr`hWW7ob&&FCuhEyofXfTJ#V90OB%YTYYw|#iqKDJj0GMwK@Y%Lzb*2G_bGtSTx(vr7!0A-X zHY!8QihhFz^yc-LWJMPj_pR+MShshrgzV#hCzVZx^mxsF+CGF=0g7G^6xo&($5mbY zRU=mL$Bvzg{1cN{v^qesy}_f-QEV5Pufbps^#z|0E2J zJyz}e*Pm0dHv$96aq&}Dc-QIF?TMP7ook+Zwz{~M`igKuIKUO}#-k`(0XumEaWYG1 zxfWQ4oQVxi%aZoGC63%h^D_sdv4n5{-+}5+6kbjPjv=^9XFKynxC}7K!Hw-JUA7_Q z+)_8%CRg@Xzp3!vh!A7s!|gQXuF?{h>9p{@R_W@r42p)=SP6W$Hc<9MUBQV5@k8F-Od+!DwicL++HXZpB zC>zZl3`18KfDYSW!={DO8_kV6_NXo&tq5jB2G*gRNnRbVz7S`AxlUu1Z1memKcl6e@BcFUqZIhcm4*geIb?&ONqhXK8GBAj}^Zx{0VTbCj)n4Q0uQ@WOY3GbL<) z4%~OMZLl?FTJv)B(5m^FE27uGo$Wf+`qR~JkfcvhC=~8aSTtitV5uFpcLBN4SYEbu za$=_8ztA~&bCdx!9ntmCFVD8LwzMq*%w*sp*>U&0XotVnRy}M8lMAL;Cjh;-Fyq)9 zPsW1|6E#io=VeCs3=S+l1BWlMtO?K|y>C7OHf>NCK>gxNa_|4+r0 z&65W0&@qMkW5V{hzyUlfzsOTVTLhUNh2P<^|1aOc>Q2L8Ezli}jT;=Gecy(kQ8oa< safbu=4pe_F$QIK3H*|aCS+%?NUyMb7$(BA=Gynhq07*qoM6N<$f|!R&8~^|S diff --git a/examples/messaging/oracle-aq-websocket-mp/src/main/resources/WEB/img/arrow-1.png b/examples/messaging/oracle-aq-websocket-mp/src/main/resources/WEB/img/arrow-1.png deleted file mode 100644 index bbba0aef8a6ce9efc80b64f1820f5eb38d83a209..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18222 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 L($S*M>{`;laxc~L diff --git a/examples/messaging/oracle-aq-websocket-mp/src/main/resources/WEB/img/frank.png b/examples/messaging/oracle-aq-websocket-mp/src/main/resources/WEB/img/frank.png deleted file mode 100644 index 51a13d8db8bc02ad1613da3b809cff394462a77a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10516 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 - - - - - - - Helidon Reactive Messaging - - - - - - - - -

      -
      -
      - -
      -
      Send
      -
      -
      -
      -
      -
      REST call /rest/messages/send/{msg}
      -
      -
      -
      Messages received from JMS over websocket
      -
      -
      -
      -
      -
      -            
      -        
      -
      -
      - - - - - \ No newline at end of file diff --git a/examples/messaging/oracle-aq-websocket-mp/src/main/resources/WEB/main.css b/examples/messaging/oracle-aq-websocket-mp/src/main/resources/WEB/main.css deleted file mode 100644 index 358c7857297..00000000000 --- a/examples/messaging/oracle-aq-websocket-mp/src/main/resources/WEB/main.css +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2020, 2021 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. - */ - -#root { - background-color: #36ABF2; - font-family: Roboto,sans-serif; - color: #fff; - position: absolute; - overflow-x: hidden; - -ms-overflow-style: none; /* Internet Explorer 10+ */ - scrollbar-width: none; /* Firefox */ - top: 0; - left: 0; - width: 100%; - height: 100%; -} -#root::-webkit-scrollbar { - display: none; /* Safari and Chrome */ -} - -#helidon { - width: 509px; - height: 273px; - position: relative; - left: -509px; - z-index: 4; - background: url('img/frank.png'); -} - -#rest-tip { - position: relative; - top: -80px; - left: 160px; -} - -#rest-tip-arrow { - width: 205px; - height: 304px; - z-index: 4; - top: -20px; - background: url('img/arrow-1.png'); -} -#rest-tip-label { - position: absolute; - white-space: nowrap; - font-size: 18px; - font-weight: bold; - z-index: 4; - left: -60px; -} - -#sse-tip { - position: absolute; - overflow: hidden; - display: flex; - width: auto; - height: auto; - top: 5%; - right: 10%; - z-index: 0; -} - -#sse-tip-arrow { - position: relative; - top: -30px; - width: 296px; - height: 262px; - z-index: 4; - background: url('img/arrow-2.png'); -} -#sse-tip-label { - position: relative; - white-space: nowrap; - font-size: 18px; - font-weight: bold; - z-index: 4; -} - -#producer { - float: left; - position: relative; - width: 300px; - height: 100%; - margin: 50px; - padding: 10px; - z-index: 99; -} - -#msgBox { - position: absolute; - width: 300px; - top: 25%; - right: 3%; - height: 100%; - margin: 50px; - padding: 10px; - z-index: 20; -} - -#input { - width: 210px; - height: 22px; - top: 58px; - left: 30px; - background-color: white; - border-radius: 10px; - border-style: solid; - border-color: white; - position: absolute; - z-index: 10; -} - -#inputCloud { - position: relative; - width: 310px; - height: 150px; - background: url('img/cloud.png'); -} - -#msg { - background-color: #D2EBFC; - color: #1A9BF4; - border-radius: 10px; - width: 300px; - height: 50px; - margin: 5px; - display: flex; - padding-left: 10px; - justify-content: center; - align-items: center; - z-index: 99; -} - -#submit { - font-weight: bold; - background-color: aqua; - color: #1A9BF4; - border-radius: 12px; - width: 100px; - height: 30px; - display: flex; - justify-content: center; - align-items: center; - margin: 5px; - cursor: pointer; -} - -#snippet { - position: absolute; - top: 15%; - left: 30%; - width: 40%; - z-index: 5; -} - -.hljs { - border-radius: 10px; - font-size: 12px; -} diff --git a/examples/messaging/oracle-aq-websocket-mp/src/main/resources/logging.properties b/examples/messaging/oracle-aq-websocket-mp/src/main/resources/logging.properties deleted file mode 100644 index 361bf5f6cbc..00000000000 --- a/examples/messaging/oracle-aq-websocket-mp/src/main/resources/logging.properties +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright (c) 2020, 2024 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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 diff --git a/examples/messaging/pom.xml b/examples/messaging/pom.xml deleted file mode 100644 index 56a44e359a2..00000000000 --- a/examples/messaging/pom.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples - helidon-examples-project - 4.1.0-SNAPSHOT - - io.helidon.examples.messaging - helidon-examples-messaging-project - Helidon Examples Messaging - pom - - - Examples of Messaging usage - - - - kafka-websocket-mp - kafka-websocket-se - jms-websocket-mp - jms-websocket-se - oracle-aq-websocket-mp - weblogic-jms-mp - - diff --git a/examples/messaging/weblogic-jms-mp/README.md b/examples/messaging/weblogic-jms-mp/README.md deleted file mode 100644 index 610a417f12d..00000000000 --- a/examples/messaging/weblogic-jms-mp/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# Helidon Messaging with Oracle Weblogic Example - -## Prerequisites -* JDK 21+ -* Maven -* Docker -* Account at https://container-registry.oracle.com/ with accepted Oracle Standard Terms and Restrictions for Weblogic. - -## Run Weblogic in docker -1. You will need to do a docker login to Oracle container registry with account which previously - accepted Oracle Standard Terms and Restrictions for Weblogic: - `docker login container-registry.oracle.com` -2. Run `bash buildAndRunWeblogic.sh` to build and run example Weblogic container. - * After example JMS resources are deployed, Weblogic console should be available at http://localhost:7001/console with `admin`/`Welcome1` -3. To obtain wlthint3client.jar necessary for connecting to Weblogic execute - `bash extractThinClientLib.sh`, file will be copied to `./weblogic` folder. - -## Build & Run -To run Helidon with thin client, flag `--add-opens=java.base/java.io=ALL-UNNAMED` is needed to -open java.base module to thin client internals. -```shell -#1. - mvn clean package -#2. - java --add-opens=java.base/java.io=ALL-UNNAMED -jar ./target/weblogic-jms-mp.jar -``` -3. Visit http://localhost:8080 and try to send and receive messages over Weblogic JMS queue. - diff --git a/examples/messaging/weblogic-jms-mp/buildAndRunWeblogic.sh b/examples/messaging/weblogic-jms-mp/buildAndRunWeblogic.sh deleted file mode 100644 index 11317c060af..00000000000 --- a/examples/messaging/weblogic-jms-mp/buildAndRunWeblogic.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash -e -# -# 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. -# - -cd ./weblogic - -# Attempt Oracle container registry login. -# You need to accept the licence agreement for Weblogic Server at https://container-registry.oracle.com/ -# Search for weblogic and accept the Oracle Standard Terms and Restrictions -docker login container-registry.oracle.com - -docker build -t wls-admin . - -docker run --rm -d \ - -p 7001:7001 \ - -p 7002:7002 \ - --name wls-admin \ - --hostname wls-admin \ - wls-admin - -printf "Waiting for WLS to start ." -while true; -do - if docker logs wls-admin | grep -q "Server state changed to RUNNING"; then - break; - fi - printf "." - sleep 5 -done -printf " [READY]\n" - -echo Deploying example JMS queues -docker exec wls-admin \ -/bin/bash \ -/u01/oracle/wlserver/common/bin/wlst.sh \ -/u01/oracle/setupTestJMSQueue.py; - -echo Example JMS queues deployed! -echo Console avaiable at http://localhost:7001/console with admin/Welcome1 -echo 'Stop Weblogic server with "docker stop wls-admin"' \ No newline at end of file diff --git a/examples/messaging/weblogic-jms-mp/extractThinClientLib.sh b/examples/messaging/weblogic-jms-mp/extractThinClientLib.sh deleted file mode 100644 index b5d6ff1b9ec..00000000000 --- a/examples/messaging/weblogic-jms-mp/extractThinClientLib.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash -e -# -# Copyright (c) 2018, 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. -# - - -# Copy wlthint3client.jar from docker container -docker cp wls-admin:/u01/oracle/wlserver/server/lib/wlthint3client.jar ./weblogic/wlthint3client.jar -# Copy DemoTrust.jks from docker container(needed if you want to try t3s protocol) -docker cp wls-admin:/u01/oracle/wlserver/server/lib/DemoTrust.jks ./weblogic/DemoTrust.jks \ No newline at end of file diff --git a/examples/messaging/weblogic-jms-mp/pom.xml b/examples/messaging/weblogic-jms-mp/pom.xml deleted file mode 100644 index 8b8fa2f3c0e..00000000000 --- a/examples/messaging/weblogic-jms-mp/pom.xml +++ /dev/null @@ -1,83 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.messaging.wls - weblogic-jms-mp - 1.0-SNAPSHOT - Helidon Examples Messaging JMS WebLogic MP - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - - io.helidon.microprofile.messaging - helidon-microprofile-messaging - - - io.helidon.messaging.wls-jms - helidon-messaging-wls-jms - - - - org.glassfish.jersey.media - jersey-media-sse - - - - io.smallrye - jandex - runtime - true - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/messaging/weblogic-jms-mp/src/main/java/io/helidon/examples/messaging/mp/FrankResource.java b/examples/messaging/weblogic-jms-mp/src/main/java/io/helidon/examples/messaging/mp/FrankResource.java deleted file mode 100644 index 1e0062b14d7..00000000000 --- a/examples/messaging/weblogic-jms-mp/src/main/java/io/helidon/examples/messaging/mp/FrankResource.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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.messaging.mp; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; - -import io.helidon.messaging.connectors.jms.JmsMessage; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.Context; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.sse.Sse; -import jakarta.ws.rs.sse.SseBroadcaster; -import jakarta.ws.rs.sse.SseEventSink; -import org.eclipse.microprofile.reactive.messaging.Channel; -import org.eclipse.microprofile.reactive.messaging.Emitter; -import org.eclipse.microprofile.reactive.messaging.Incoming; -import org.glassfish.jersey.media.sse.OutboundEvent; - -/** - * SSE Jax-Rs resource for message publishing and consuming. - */ -@Path("/frank") -@ApplicationScoped -public class FrankResource { - - @Inject - @Channel("to-wls") - private Emitter emitter; - private SseBroadcaster sseBroadcaster; - - /** - * Consuming JMS messages from Weblogic and sending them to the client over SSE. - * - * @param msg dequeued message - * @return completion stage marking end of the processing - */ - @Incoming("from-wls") - public CompletionStage receive(JmsMessage msg) { - if (sseBroadcaster == null) { - System.out.println("No SSE client subscribed yet: " + msg.getPayload()); - return CompletableFuture.completedStage(null); - } - sseBroadcaster.broadcast(new OutboundEvent.Builder().data(msg.getPayload()).build()); - return CompletableFuture.completedStage(null); - } - - /** - * Send message to Weblogic JMS queue. - * - * @param msg message to be sent - */ - @POST - @Path("/send/{msg}") - public void send(@PathParam("msg") String msg) { - emitter.send(msg); - } - - /** - * Register SSE client to listen for messages coming from Weblogic JMS. - * - * @param eventSink client sink - * @param sse SSE context - */ - @GET - @Path("sse") - @Produces(MediaType.SERVER_SENT_EVENTS) - public void listenToEvents(@Context SseEventSink eventSink, @Context Sse sse) { - if (sseBroadcaster == null) { - sseBroadcaster = sse.newBroadcaster(); - } - sseBroadcaster.register(eventSink); - } -} diff --git a/examples/messaging/weblogic-jms-mp/src/main/java/io/helidon/examples/messaging/mp/package-info.java b/examples/messaging/weblogic-jms-mp/src/main/java/io/helidon/examples/messaging/mp/package-info.java deleted file mode 100644 index 372cec04320..00000000000 --- a/examples/messaging/weblogic-jms-mp/src/main/java/io/helidon/examples/messaging/mp/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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. - */ - -/** - * Helidon MP Reactive Messaging with Weblogic JMS. - */ -package io.helidon.examples.messaging.mp; diff --git a/examples/messaging/weblogic-jms-mp/src/main/resources/META-INF/beans.xml b/examples/messaging/weblogic-jms-mp/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 80727f9c7fd..00000000000 --- a/examples/messaging/weblogic-jms-mp/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - diff --git a/examples/messaging/weblogic-jms-mp/src/main/resources/WEB/favicon.ico b/examples/messaging/weblogic-jms-mp/src/main/resources/WEB/favicon.ico deleted file mode 100644 index d91659fdb53c934af789e9b93e2d92c679f975d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1230 zcmV;<1Tp)GP)*8l(j8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H11WQRoK~z|Uy_Z{T6lE00e`jX8mqMWtT1?w51zW;RQDQ<{=()Hdzz zw!1sW2fMg*x83dr`hWW7ob&&FCuhEyofXfTJ#V90OB%YTYYw|#iqKDJj0GMwK@Y%Lzb*2G_bGtSTx(vr7!0A-X zHY!8QihhFz^yc-LWJMPj_pR+MShshrgzV#hCzVZx^mxsF+CGF=0g7G^6xo&($5mbY zRU=mL$Bvzg{1cN{v^qesy}_f-QEV5Pufbps^#z|0E2J zJyz}e*Pm0dHv$96aq&}Dc-QIF?TMP7ook+Zwz{~M`igKuIKUO}#-k`(0XumEaWYG1 zxfWQ4oQVxi%aZoGC63%h^D_sdv4n5{-+}5+6kbjPjv=^9XFKynxC}7K!Hw-JUA7_Q z+)_8%CRg@Xzp3!vh!A7s!|gQXuF?{h>9p{@R_W@r42p)=SP6W$Hc<9MUBQV5@k8F-Od+!DwicL++HXZpB zC>zZl3`18KfDYSW!={DO8_kV6_NXo&tq5jB2G*gRNnRbVz7S`AxlUu1Z1memKcl6e@BcFUqZIhcm4*geIb?&ONqhXK8GBAj}^Zx{0VTbCj)n4Q0uQ@WOY3GbL<) z4%~OMZLl?FTJv)B(5m^FE27uGo$Wf+`qR~JkfcvhC=~8aSTtitV5uFpcLBN4SYEbu za$=_8ztA~&bCdx!9ntmCFVD8LwzMq*%w*sp*>U&0XotVnRy}M8lMAL;Cjh;-Fyq)9 zPsW1|6E#io=VeCs3=S+l1BWlMtO?K|y>C7OHf>NCK>gxNa_|4+r0 z&65W0&@qMkW5V{hzyUlfzsOTVTLhUNh2P<^|1aOc>Q2L8Ezli}jT;=Gecy(kQ8oa< safbu=4pe_F$QIK3H*|aCS+%?NUyMb7$(BA=Gynhq07*qoM6N<$f|!R&8~^|S diff --git a/examples/messaging/weblogic-jms-mp/src/main/resources/WEB/img/arrow-1.png b/examples/messaging/weblogic-jms-mp/src/main/resources/WEB/img/arrow-1.png deleted file mode 100644 index bbba0aef8a6ce9efc80b64f1820f5eb38d83a209..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18222 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 L($S*M>{`;laxc~L diff --git a/examples/messaging/weblogic-jms-mp/src/main/resources/WEB/img/frank.png b/examples/messaging/weblogic-jms-mp/src/main/resources/WEB/img/frank.png deleted file mode 100644 index 51a13d8db8bc02ad1613da3b809cff394462a77a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10516 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 - - - - - - Helidon Reactive Messaging - - - - - -
      -
      -
      - -
      -
      Send
      -
      -
      -
      -
      -
      REST call /frank/send/{msg}
      -
      -
      -
      SSE messages received
      -
      -
      -
      -
      - - - - - \ No newline at end of file diff --git a/examples/messaging/weblogic-jms-mp/src/main/resources/WEB/main.css b/examples/messaging/weblogic-jms-mp/src/main/resources/WEB/main.css deleted file mode 100644 index 496dde4fe6c..00000000000 --- a/examples/messaging/weblogic-jms-mp/src/main/resources/WEB/main.css +++ /dev/null @@ -1,171 +0,0 @@ -/* - * 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. - */ -#root { - background-color: #36ABF2; - font-family: Roboto,sans-serif; - color: #fff; - position: absolute; - overflow-x: hidden; - -ms-overflow-style: none; /* Internet Explorer 10+ */ - scrollbar-width: none; /* Firefox */ - top: 0; - left: 0; - width: 100%; - height: 100%; -} -#root::-webkit-scrollbar { - display: none; /* Safari and Chrome */ -} - -#helidon { - width: 509px; - height: 273px; - position: relative; - left: -509px; - z-index: 4; - background: url('img/frank.png'); -} - -#rest-tip { - position: relative; - top: -80px; - left: 160px; -} - -#rest-tip-arrow { - width: 205px; - height: 304px; - z-index: 4; - top: -20px; - background: url('img/arrow-1.png'); -} -#rest-tip-label { - position: absolute; - white-space: nowrap; - font-size: 18px; - font-weight: bold; - z-index: 4; - left: -60px; -} - -#sse-tip { - position: absolute; - overflow: hidden; - display: flex; - width: auto; - height: auto; - top: 5%; - right: 10%; - z-index: 0; -} - -#sse-tip-arrow { - position: relative; - top: -30px; - width: 296px; - height: 262px; - z-index: 4; - background: url('img/arrow-2.png'); -} -#sse-tip-label { - position: relative; - white-space: nowrap; - font-size: 18px; - font-weight: bold; - z-index: 4; -} - -#producer { - float: left; - position: relative; - width: 300px; - height: 100%; - margin: 50px; - padding: 10px; - z-index: 99; -} - -#msgBox { - position: absolute; - width: 300px; - top: 25%; - right: 3%; - height: 100%; - margin: 50px; - padding: 10px; - z-index: 20; -} - -#input { - width: 210px; - height: 22px; - top: 58px; - left: 30px; - background-color: white; - border-radius: 10px; - border-style: solid; - border-color: white; - position: absolute; - z-index: 10; -} - -#inputCloud { - position: relative; - width: 310px; - height: 150px; - background: url('img/cloud.png'); -} - -#msg { - background-color: #D2EBFC; - color: #1A9BF4; - border-radius: 10px; - width: 300px; - height: 50px; - margin: 5px; - display: flex; - padding-left: 10px; - justify-content: center; - align-items: center; - z-index: 99; -} - -#submit { - font-weight: bold; - background-color: aqua; - color: #1A9BF4; - border-radius: 12px; - width: 100px; - height: 30px; - display: flex; - justify-content: center; - align-items: center; - margin: 5px; - cursor: pointer; -} - -#snippet { - position: absolute; - top: 15%; - left: 30%; - width: 40%; - z-index: 5; -} - -.hljs { - border-radius: 10px; - font-size: 12px; -} \ No newline at end of file diff --git a/examples/messaging/weblogic-jms-mp/src/main/resources/application.yaml b/examples/messaging/weblogic-jms-mp/src/main/resources/application.yaml deleted file mode 100644 index f987d99b972..00000000000 --- a/examples/messaging/weblogic-jms-mp/src/main/resources/application.yaml +++ /dev/null @@ -1,44 +0,0 @@ -# -# Copyright (c) 2022, 2023 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 - static: - classpath: - location: /WEB - welcome: index.html - -mp: - messaging: - connector: - helidon-weblogic-jms: - # JMS factory configured in Weblogic - jms-factory: jms/TestConnectionFactory - # Path to the WLS Thin T3 client jar(extract it from docker container with extractThinClientLib.sh) - thin-jar: weblogic/wlthint3client.jar - url: "t3://localhost:7001" - producer.unit-of-order: kec1 - incoming: - from-wls: - connector: helidon-weblogic-jms - # WebLogic CDI Syntax(CDI stands for Create Destination Identifier) - destination: ./TestJMSModule!TestQueue - outgoing: - to-wls: - connector: helidon-weblogic-jms - # JNDI identifier for the same queue - jndi.destination: jms/TestQueue \ No newline at end of file diff --git a/examples/messaging/weblogic-jms-mp/src/main/resources/logging.properties b/examples/messaging/weblogic-jms-mp/src/main/resources/logging.properties deleted file mode 100644 index 1ac57eb5b92..00000000000 --- a/examples/messaging/weblogic-jms-mp/src/main/resources/logging.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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.level=INFO diff --git a/examples/messaging/weblogic-jms-mp/weblogic/Dockerfile b/examples/messaging/weblogic-jms-mp/weblogic/Dockerfile deleted file mode 100644 index 6e79458ebd5..00000000000 --- a/examples/messaging/weblogic-jms-mp/weblogic/Dockerfile +++ /dev/null @@ -1,54 +0,0 @@ -# -# 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. -# - -# ORACLE DOCKERFILES PROJECT -# -------------------------- -# This docker file is customized, originaly taken from https://github.com/oracle/docker-images -# and extends the Oracle WebLogic image by creating a sample domain. -# -# Base image is available at https://container-registry.oracle.com/ -# -FROM container-registry.oracle.com/middleware/weblogic:14.1.1.0-dev-11 - -ENV ORACLE_HOME=/u01/oracle \ - USER_MEM_ARGS="-Djava.security.egd=file:/dev/./urandom" \ - SCRIPT_FILE=/u01/oracle/createAndStartEmptyDomain.sh \ - HEALTH_SCRIPT_FILE=/u01/oracle/get_healthcheck_url.sh \ - PATH=$PATH:${JAVA_HOME}/bin:/u01/oracle/oracle_common/common/bin:/u01/oracle/wlserver/common/bin - -ENV DOMAIN_NAME="${DOMAIN_NAME:-base_domain}" \ - ADMIN_LISTEN_PORT="${ADMIN_LISTEN_PORT:-7001}" \ - ADMIN_NAME="${ADMIN_NAME:-AdminServer}" \ - DEBUG_FLAG=true \ - PRODUCTION_MODE=dev \ - ADMINISTRATION_PORT_ENABLED="${ADMINISTRATION_PORT_ENABLED:-true}" \ - ADMINISTRATION_PORT="${ADMINISTRATION_PORT:-9002}" - -COPY container-scripts/createAndStartEmptyDomain.sh container-scripts/get_healthcheck_url.sh /u01/oracle/ -COPY container-scripts/create-wls-domain.py container-scripts/setupTestJMSQueue.py /u01/oracle/ -COPY properties/domain.properties /u01/oracle/properties/ - -USER root - -RUN chmod +xr $SCRIPT_FILE $HEALTH_SCRIPT_FILE && \ - chown oracle:root $SCRIPT_FILE /u01/oracle/create-wls-domain.py $HEALTH_SCRIPT_FILE - -USER oracle - -HEALTHCHECK --start-period=10s --timeout=30s --retries=3 CMD curl -k -s --fail `$HEALTH_SCRIPT_FILE` || exit 1 -WORKDIR ${ORACLE_HOME} - -CMD ["/u01/oracle/createAndStartEmptyDomain.sh"] \ No newline at end of file diff --git a/examples/messaging/weblogic-jms-mp/weblogic/container-scripts/create-wls-domain.py b/examples/messaging/weblogic-jms-mp/weblogic/container-scripts/create-wls-domain.py deleted file mode 100644 index e24167e1fb1..00000000000 --- a/examples/messaging/weblogic-jms-mp/weblogic/container-scripts/create-wls-domain.py +++ /dev/null @@ -1,104 +0,0 @@ -# -# 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. -# - -# -# WebLogic on Docker Default Domain -# -# Domain, as defined in DOMAIN_NAME, will be created in this script. Name defaults to 'base_domain'. -# -# Since : October, 2014 -# Author: monica.riccelli@oracle.com -# ============================================== -domain_name = os.environ.get("DOMAIN_NAME", "base_domain") -admin_name = os.environ.get("ADMIN_NAME", "AdminServer") -admin_listen_port = int(os.environ.get("ADMIN_LISTEN_PORT", "7001")) -domain_path = '/u01/oracle/user_projects/domains/%s' % domain_name -production_mode = os.environ.get("PRODUCTION_MODE", "prod") -administration_port_enabled = os.environ.get("ADMINISTRATION_PORT_ENABLED", "true") -administration_port = int(os.environ.get("ADMINISTRATION_PORT", "9002")) - -print('domain_name : [%s]' % domain_name); -print('admin_listen_port : [%s]' % admin_listen_port); -print('domain_path : [%s]' % domain_path); -print('production_mode : [%s]' % production_mode); -print('admin name : [%s]' % admin_name); -print('administration_port_enabled : [%s]' % administration_port_enabled); -print('administration_port : [%s]' % administration_port); - -# Open default domain template -# ============================ -readTemplate("/u01/oracle/wlserver/common/templates/wls/wls.jar") - -set('Name', domain_name) -setOption('DomainName', domain_name) - -# Set Administration Port -# ======================= -if administration_port_enabled != "false": - set('AdministrationPort', administration_port) - set('AdministrationPortEnabled', 'false') - -# Disable Admin Console -# -------------------- -# cmo.setConsoleEnabled(false) - -# Configure the Administration Server and SSL port. -# ================================================= -cd('/Servers/AdminServer') -set('Name', admin_name) -set('ListenAddress', '') -set('ListenPort', admin_listen_port) -if administration_port_enabled != "false": - create(admin_name, 'SSL') - cd('SSL/' + admin_name) - set('Enabled', 'True') - -# Define the user password for weblogic -# ===================================== -cd(('/Security/%s/User/weblogic') % domain_name) -cmo.setName(username) -cmo.setPassword(password) - -# Write the domain and close the domain template -# ============================================== -setOption('OverwriteDomain', 'true') -setOption('ServerStartMode',production_mode) - -# Create Node Manager -# =================== -#cd('/NMProperties') -#set('ListenAddress','') -#set('ListenPort',5556) -#set('CrashRecoveryEnabled', 'true') -#set('NativeVersionEnabled', 'true') -#set('StartScriptEnabled', 'false') -#set('SecureListener', 'false') -#set('LogLevel', 'FINEST') - -# Set the Node Manager user name and password -# =========================================== -#cd('/SecurityConfiguration/%s' % domain_name) -#set('NodeManagerUsername', username) -#set('NodeManagerPasswordEncrypted', password) - -# Write Domain -# ============ -writeDomain(domain_path) -closeTemplate() - -# Exit WLST -# ========= -exit() diff --git a/examples/messaging/weblogic-jms-mp/weblogic/container-scripts/createAndStartEmptyDomain.sh b/examples/messaging/weblogic-jms-mp/weblogic/container-scripts/createAndStartEmptyDomain.sh deleted file mode 100644 index a87a296315b..00000000000 --- a/examples/messaging/weblogic-jms-mp/weblogic/container-scripts/createAndStartEmptyDomain.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2022, 2024 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. -# - -# If AdminServer.log does not exists, container is starting for 1st time -# So it should start NM and also associate with AdminServer -# Otherwise, only start NM (container restarted) -########### SIGTERM handler ############ -function _term() { - echo "Stopping container." - echo "SIGTERM received, shutting down the server!" - "${DOMAIN_HOME}/bin/stopWebLogic.sh" -} - -# Set SIGTERM handler -trap _term SIGTERM - -DOMAIN_NAME="base_domain" -DOMAIN_HOME="/u01/oracle/user_projects/domains/${DOMAIN_NAME}" -export DOMAIN_NAME DOMAIN_HOME -echo "Domain Home is: " "${DOMAIN_HOME}" - -mkdir -p "${ORACLE_HOME}/properties" -# Create Domain only if 1st execution -if [ ! -e "${DOMAIN_HOME}/servers/${ADMIN_NAME}/logs/${ADMIN_NAME}.log" ]; then - echo "Create Domain" - PROPERTIES_FILE="/u01/oracle/properties/domain.properties" - if [ ! -e "${PROPERTIES_FILE}" ]; then - echo "A properties file with the username and password needs to be supplied." - exit - fi - - # Get Username - USER=$(awk '{print $1}' ${PROPERTIES_FILE} | grep username | cut -d "=" -f2) - if [ -z "${USER}" ]; then - echo "The domain username is blank. The Admin username must be set in the properties file." - exit - fi - - # Get Password - PASS=$(awk '{print $1}' ${PROPERTIES_FILE} | grep password | cut -d "=" -f2) - if [ -z "${PASS}" ]; then - echo "The domain password is blank. The Admin password must be set in the properties file." - exit - fi - - # Create an empty domain - wlst.sh -skipWLSModuleScanning -loadProperties $PROPERTIES_FILE /u01/oracle/create-wls-domain.py - mkdir -p "${DOMAIN_HOME}/servers/${ADMIN_NAME}/security/" - chmod -R g+w "${DOMAIN_HOME}" - echo "username=${USER}" >> "${DOMAIN_HOME}/servers/${ADMIN_NAME}/security/boot.properties" - echo "password=${PASS}" >> "${DOMAIN_HOME}/servers/${ADMIN_NAME}/security/boot.properties" - "${DOMAIN_HOME}/bin/setDomainEnv.sh" - # Setup JMS examples -# wlst.sh -skipWLSModuleScanning -loadProperties $PROPERTIES_FILE /u01/oracle/setupTestJMSQueue.py -fi - -# Start Admin Server and tail the logs -"${DOMAIN_HOME}/startWebLogic.sh" -if [ -e "${DOMAIN_HOME}/servers/${ADMIN_NAME}/logs/${ADMIN_NAME}.log" ]; then - echo "${DOMAIN_HOME}/servers/${ADMIN_NAME}/logs/${ADMIN_NAME}.log" -fi -touch "${DOMAIN_HOME}/servers/${ADMIN_NAME}/logs/${ADMIN_NAME}.log" -tail -f "${DOMAIN_HOME}/servers/${ADMIN_NAME}/logs/${ADMIN_NAME}.log" - -childPID=${!} -wait ${childPID} diff --git a/examples/messaging/weblogic-jms-mp/weblogic/container-scripts/get_healthcheck_url.sh b/examples/messaging/weblogic-jms-mp/weblogic/container-scripts/get_healthcheck_url.sh deleted file mode 100644 index 5eb3ded88e4..00000000000 --- a/examples/messaging/weblogic-jms-mp/weblogic/container-scripts/get_healthcheck_url.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash -# -# 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. -# - -if [ "$ADMINISTRATION_PORT_ENABLED" = "true" ] ; then - echo "https://{localhost:$ADMINISTRATION_PORT}/weblogic/ready" ; -else - echo "http://{localhost:$ADMIN_LISTEN_PORT}/weblogic/ready" ; -fi diff --git a/examples/messaging/weblogic-jms-mp/weblogic/container-scripts/setupTestJMSQueue.py b/examples/messaging/weblogic-jms-mp/weblogic/container-scripts/setupTestJMSQueue.py deleted file mode 100644 index 3269b782ae0..00000000000 --- a/examples/messaging/weblogic-jms-mp/weblogic/container-scripts/setupTestJMSQueue.py +++ /dev/null @@ -1,115 +0,0 @@ -# -# 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. -# - -import os.path -import sys - -System.setProperty("weblogic.security.SSL.ignoreHostnameVerification", "true") - -connect("admin","Welcome1","t3://localhost:7001") -adm_name=get('AdminServerName') -sub_deployment_name="TestJMSSubdeployment" -jms_module_name="TestJMSModule" -queue_name="TestQueue" -factory_name="TestConnectionFactory" -jms_server_name="TestJMSServer" - - -def createJMSServer(adm_name, jms_server_name): - cd('/JMSServers') - if (len(ls(returnMap='true')) == 0): - print 'No JMS Server found, creating ' + jms_server_name - cd('/') - cmo.createJMSServer(jms_server_name) - cd('/JMSServers/'+jms_server_name) - cmo.addTarget(getMBean("/Servers/" + adm_name)) - - -def createJMSModule(jms_module_name, adm_name, sub_deployment_name): - print "Creating JMS module " + jms_module_name - cd('/JMSServers') - jms_servers=ls(returnMap='true') - cd('/') - module = create(jms_module_name, "JMSSystemResource") - module.addTarget(getMBean("Servers/"+adm_name)) - cd('/SystemResources/'+jms_module_name) - module.createSubDeployment(sub_deployment_name) - cd('/SystemResources/'+jms_module_name+'/SubDeployments/'+sub_deployment_name) - - list=[] - for i in jms_servers: - list.append(ObjectName(str('com.bea:Name='+i+',Type=JMSServer'))) - set('Targets',jarray.array(list, ObjectName)) - -def getJMSModulePath(jms_module_name): - jms_module_path = "/JMSSystemResources/"+jms_module_name+"/JMSResource/"+jms_module_name - return jms_module_path - -def createJMSQueue(jms_module_name,jms_queue_name): - print "Creating JMS queue " + jms_queue_name - jms_module_path = getJMSModulePath(jms_module_name) - cd(jms_module_path) - cmo.createQueue(jms_queue_name) - cd(jms_module_path+'/Queues/'+jms_queue_name) - cmo.setJNDIName("jms/" + jms_queue_name) - cmo.setSubDeploymentName(sub_deployment_name) - -def createDistributedJMSQueue(jms_module_name,jms_queue_name): - print "Creating distributed JMS queue " + jms_queue_name - jms_module_path = getJMSModulePath(jms_module_name) - cd(jms_module_path) - cmo.createDistributedQueue(jms_queue_name) - cd(jms_module_path+'/DistributedQueues/'+jms_queue_name) - cmo.setJNDIName("jms/" + jms_queue_name) - -def addMemberQueue(udd_name,queue_name): - jms_module_path = getJMSModulePath(jms_module_name) - cd(jms_module_path+'/DistributedQueues/'+udd_name) - cmo.setLoadBalancingPolicy('Round-Robin') - cmo.createDistributedQueueMember(queue_name) - -def createJMSFactory(jms_module_name,jms_fact_name): - print "Creating JMS connection factory " + jms_fact_name - jms_module_path = getJMSModulePath(jms_module_name) - cd(jms_module_path) - cmo.createConnectionFactory(jms_fact_name) - cd(jms_module_path+'/ConnectionFactories/'+jms_fact_name) - cmo.setJNDIName("jms/" + jms_fact_name) - cmo.setSubDeploymentName(sub_deployment_name) - - - -edit() -startEdit() - -print "Server name: "+adm_name - -createJMSServer(adm_name,jms_server_name) -createJMSModule(jms_module_name,adm_name,sub_deployment_name) -createJMSFactory(jms_module_name,factory_name) -createJMSQueue(jms_module_name,queue_name) - -### Unified Distributed Destinations(UDD) example -createDistributedJMSQueue(jms_module_name,"udd_queue") -# Normally member queues would be in different sub-deployments -createJMSQueue(jms_module_name,"ms1@udd_queue") -createJMSQueue(jms_module_name,"ms2@udd_queue") -addMemberQueue("udd_queue", "ms1@udd_queue") -addMemberQueue("udd_queue", "ms2@udd_queue") - -save() -activate(block="true") -disconnect() \ No newline at end of file diff --git a/examples/messaging/weblogic-jms-mp/weblogic/properties/domain.properties b/examples/messaging/weblogic-jms-mp/weblogic/properties/domain.properties deleted file mode 100644 index 6e9a5fc4b19..00000000000 --- a/examples/messaging/weblogic-jms-mp/weblogic/properties/domain.properties +++ /dev/null @@ -1,35 +0,0 @@ -# -# 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. -# - -# Env properties inherited from base image -DOMAIN_NAME=myDomain -ADMIN_LISTEN_PORT=7001 -ADMIN_NAME=myadmin -PRODUCTION_MODE=dev -DEBUG_FLAG=true -ADMINISTRATION_PORT_ENABLED=false -ADMINISTRATION_PORT=9002 -# Env properties for this image -ADMIN_HOST=AdminContainer -MANAGED_SERVER_PORT=8001 -MANAGED_SERVER_NAME_BASE=MS -CONFIGURED_MANAGED_SERVER_COUNT=2 -PRODUCTION_MODE_ENABLED=true -CLUSTER_NAME=cluster1 -CLUSTER_TYPE=DYNAMIC -DOMAIN_HOST_VOLUME=/Users/host/temp -username=admin -password=Welcome1 \ No newline at end of file diff --git a/examples/messaging/weblogic-jms-mp/weblogic/properties/domain_security.properties b/examples/messaging/weblogic-jms-mp/weblogic/properties/domain_security.properties deleted file mode 100644 index fcfb1d90fff..00000000000 --- a/examples/messaging/weblogic-jms-mp/weblogic/properties/domain_security.properties +++ /dev/null @@ -1,18 +0,0 @@ -# -# 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. -# - -username=admin -password=Welcome1 \ No newline at end of file diff --git a/examples/metrics/exemplar/README.md b/examples/metrics/exemplar/README.md deleted file mode 100644 index fd9bcf65ed1..00000000000 --- a/examples/metrics/exemplar/README.md +++ /dev/null @@ -1,67 +0,0 @@ -# Helidon Metrics Exemplar SE Example - -This project implements a simple Hello World REST service using Helidon SE and demonstrates the -optional metrics exemplar support. - -## Start Zipkin (optional) -If you do not start Zipkin, the example app will still function correctly but it will log a warning -when it cannot contact the Zipkin server to report the tracing spans. Even so, the metrics output -will contain valid exemplars. - -With Docker: -```shell -docker run --name zipkin -d -p 9411:9411 openzipkin/zipkin -``` - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-metrics-exemplar.jar -``` - -## Exercise the application - -```shell -curl -X GET http://localhost:8080/greet -#output: {"message":"Hello World!"} - -curl -X GET http://localhost:8080/greet/Joe -#output: {"message":"Hello Joe!"} - -curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}' http://localhost:8080/greet/greeting - -curl -X GET http://localhost:8080/greet/Jose -#output: {"message":"Hola Jose!"} - -curl -X GET http://localhost:8080/greet -#output: {"message":"Hola World!"} -``` - -## Retrieve application metrics - -``` -# Prometheus format with exemplars - -curl -s -X GET http://localhost:8080/observe/metrics/application -# TYPE application_counterForPersonalizedGreetings_total counter -# HELP application_counterForPersonalizedGreetings_total -application_counterForPersonalizedGreetings_total 2 # {trace_id="78e61eed351f4c9d"} 1 1617812495.016000 -. . . -# TYPE application_timerForGets_mean_seconds gauge -application_timerForGets_mean_seconds 0.005772598385062112 # {trace_id="b22f13c37ba8b879"} 0.001563945 1617812578.687000 -# TYPE application_timerForGets_max_seconds gauge -application_timerForGets_max_seconds 0.028018165 # {trace_id="a1b127002725143c"} 0.028018165 1617812467.524000 -``` -The exemplars contain `trace_id` values tying them to specific samples. -Note that the exemplar for the counter refers to the most recent update to the counter. - -For the timer, the value for the `max` is exactly the same as the value for its exemplar, -because the `max` value has to come from at least one sample. -In contrast, Helidon calculates the `mean` value from possibly multiple samples. The exemplar for -`mean` is a sample with value as close as that of other samples to the mean. - -## Browse the Zipkin traces -If you started the Zipkin server, visit `http://localhost:9411` and click `Run Query` to see all -the spans your Helidon application reported to Zipkin. -You can compare the trace IDs in the Zipkin display to those in the metrics output. diff --git a/examples/metrics/exemplar/pom.xml b/examples/metrics/exemplar/pom.xml deleted file mode 100644 index 94110c96bfa..00000000000 --- a/examples/metrics/exemplar/pom.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - 4.0.0 - - io.helidon.examples.metrics - helidon-examples-metrics-exemplar - - Helidon Examples Metrics Exemplar - - - io.helidon.examples.metrics.exemplar.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.http.media - helidon-http-media-jsonp - - - io.helidon.webserver.observe - helidon-webserver-observe - - - io.helidon.webserver.observe - helidon-webserver-observe-metrics - - - io.helidon.webserver.observe - helidon-webserver-observe-health - - - io.helidon.webserver.observe - helidon-webserver-observe-tracing - - - io.helidon.metrics - helidon-metrics-system-meters - runtime - - - io.helidon.logging - helidon-logging-jul - runtime - - - io.helidon.tracing - helidon-tracing - - - io.helidon.metrics - helidon-metrics-trace-exemplar - - - io.helidon.tracing.providers - helidon-tracing-providers-zipkin - - - io.helidon.config - helidon-config-yaml - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/metrics/exemplar/src/main/java/io/helidon/examples/metrics/exemplar/GreetService.java b/examples/metrics/exemplar/src/main/java/io/helidon/examples/metrics/exemplar/GreetService.java deleted file mode 100644 index f091be1225e..00000000000 --- a/examples/metrics/exemplar/src/main/java/io/helidon/examples/metrics/exemplar/GreetService.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.metrics.exemplar; - -import java.util.Collections; -import java.util.concurrent.atomic.AtomicReference; - -import io.helidon.config.Config; -import io.helidon.http.Status; -import io.helidon.metrics.api.Counter; -import io.helidon.metrics.api.Meter; -import io.helidon.metrics.api.MeterRegistry; -import io.helidon.metrics.api.Metrics; -import io.helidon.metrics.api.Timer; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; - -/** - * 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 HttpService { - - /** - * The config value for the key {@code greeting}. - */ - private final AtomicReference greeting = new AtomicReference<>(); - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - static final String TIMER_FOR_GETS = "timerForGets"; - static final String COUNTER_FOR_PERSONALIZED_GREETINGS = "counterForPersonalizedGreetings"; - - private final Timer timerForGets; - private final Counter personalizedGreetingsCounter; - - GreetService() { - Config config = Config.global(); - greeting.set(config.get("app.greeting").asString().orElse("Ciao")); - - MeterRegistry meterRegistry = Metrics.globalRegistry(); - timerForGets = meterRegistry.getOrCreate(Timer.builder(TIMER_FOR_GETS) - .baseUnit(Meter.BaseUnits.NANOSECONDS)); - personalizedGreetingsCounter = meterRegistry.getOrCreate(Counter.builder(COUNTER_FOR_PERSONALIZED_GREETINGS)); - } - - /** - * A service registers itself by updating the routing rules. - * - * @param rules the routing rules. - */ - @Override - public void routing(HttpRules rules) { - rules.get("/", this::timeGet, this::getDefaultMessageHandler) - .get("/{name}", this::countPersonalized, 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().pathParameters().get("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 void updateGreetingFromJson(JsonObject jo, ServerResponse response) { - - if (!jo.containsKey("greeting")) { - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "No greeting provided") - .build(); - response.status(Status.BAD_REQUEST_400) - .send(jsonErrorObject); - return; - } - - greeting.set(jo.getString("greeting")); - response.status(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) { - JsonObject jsonObject = request.content().as(JsonObject.class); - updateGreetingFromJson(jsonObject, response); - } - - private void timeGet(ServerRequest request, ServerResponse response) { - timerForGets.record((Runnable) response::next); - } - - private void countPersonalized(ServerRequest request, ServerResponse response) { - personalizedGreetingsCounter.increment(); - response.next(); - } -} diff --git a/examples/metrics/exemplar/src/main/java/io/helidon/examples/metrics/exemplar/Main.java b/examples/metrics/exemplar/src/main/java/io/helidon/examples/metrics/exemplar/Main.java deleted file mode 100644 index 53f9e7f5937..00000000000 --- a/examples/metrics/exemplar/src/main/java/io/helidon/examples/metrics/exemplar/Main.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.metrics.exemplar; - -import io.helidon.config.Config; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.http.HttpRouting; - -/** - * 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(String[] args) { - WebServerConfig.Builder builder = WebServer.builder(); - setup(builder); - WebServer server = builder.build().start(); - System.out.println("WEB server is up! http://localhost:" + server.port() + "/greet"); - } - - /** - * Set up the server. - * - * @param server server builder - */ - static void setup(WebServerConfig.Builder server) { - // load logging configuration - LogConfig.configureRuntime(); - - // By default, this will pick up application.yaml from the classpath - Config config = Config.create(); - Config.global(config); - - server.routing(Main::routing) - .config(config.get("server")); - - } - - /** - * Setup routing. - * - * @param routing routing builder - */ - static void routing(HttpRouting.Builder routing) { - routing.register("/greet", new GreetService()); - } -} diff --git a/examples/metrics/exemplar/src/main/java/io/helidon/examples/metrics/exemplar/package-info.java b/examples/metrics/exemplar/src/main/java/io/helidon/examples/metrics/exemplar/package-info.java deleted file mode 100644 index 8a1399656a7..00000000000 --- a/examples/metrics/exemplar/src/main/java/io/helidon/examples/metrics/exemplar/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2021 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. - */ - -/** - * Quickstart demo application - *

      - * Start with {@link io.helidon.examples.metrics.exemplar.Main} class. - *

      - * @see io.helidon.examples.metrics.exemplar.Main - */ -package io.helidon.examples.metrics.exemplar; diff --git a/examples/metrics/exemplar/src/main/resources/application.yaml b/examples/metrics/exemplar/src/main/resources/application.yaml deleted file mode 100644 index cd0177a4f50..00000000000 --- a/examples/metrics/exemplar/src/main/resources/application.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# -# Copyright (c) 2021, 2023 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. -# - -app: - greeting: "Hello" - -server: - port: 8080 - host: 0.0.0.0 -tracing: - service: "hello-world" diff --git a/examples/metrics/exemplar/src/main/resources/logging.properties b/examples/metrics/exemplar/src/main/resources/logging.properties deleted file mode 100644 index c916a0505a0..00000000000 --- a/examples/metrics/exemplar/src/main/resources/logging.properties +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright (c) 2021, 2024 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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 diff --git a/examples/metrics/exemplar/src/test/java/io/helidon/examples/metrics/exemplar/MainTest.java b/examples/metrics/exemplar/src/test/java/io/helidon/examples/metrics/exemplar/MainTest.java deleted file mode 100644 index 64dfca93acb..00000000000 --- a/examples/metrics/exemplar/src/test/java/io/helidon/examples/metrics/exemplar/MainTest.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.metrics.exemplar; - -import java.io.LineNumberReader; -import java.io.StringReader; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; - -import io.helidon.common.media.type.MediaTypes; -import io.helidon.config.Config; -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.WebServerConfig; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertLinesMatch; - -@ServerTest -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 final Http1Client client; - - public MainTest(Http1Client client) { - this.client = client; - } - - @SetUpServer - public static void setup(WebServerConfig.Builder server) { - Config.global(Config.create()); - server.routing(Main::routing); - } - - @Test - public void testHelloWorld() { - try (Http1ClientResponse response = client.get("/greet").request()) { - assertThat(response.as(JsonObject.class).getString("message"), is("Hello World!")); - } - - try (Http1ClientResponse response = client.get("/greet/Joe").request()) { - assertThat(response.as(JsonObject.class).getString("message"), is("Hello Joe!")); - } - - try (Http1ClientResponse response = client.put("/greet/greeting").submit(TEST_JSON_OBJECT)) { - assertThat(response.status().code(), is(204)); - } - - try (Http1ClientResponse response = client.get("/greet/Joe").request()) { - assertThat(response.as(JsonObject.class).getString("message"), is("Hola Joe!")); - } - - try (Http1ClientResponse response = client.get("/observe/metrics").request()) { - assertThat(response.status().code(), is(200)); - } - } - - @Disabled // because of intermittent pipeline failures; the assertLinesMatch exhausts the available lines - @Test - public void testMetrics() { - try (Http1ClientResponse response = client.get("/greet").request()) { - assertThat(response.as(String.class), containsString("Hello World!")); - } - - try (Http1ClientResponse response = client.get("/greet/Joe").request()) { - assertThat(response.as(String.class), containsString("Hello Joe!")); - } - - try (Http1ClientResponse response = client.get("/observe/metrics/application") - .accept(MediaTypes.APPLICATION_OPENMETRICS_TEXT) - .request()) { - - String openMetricsOutput = response.as(String.class); - LineNumberReader reader = new LineNumberReader(new StringReader(openMetricsOutput)); - List returnedLines = reader.lines() - .collect(Collectors.toList()); - returnedLines.add("# extra line at end to make sure we do not deplete the actual lines"); - - List expected = List.of(">> skip to max >>", - "# TYPE " + GreetService.COUNTER_FOR_PERSONALIZED_GREETINGS + " counter", - "# HELP " + GreetService.COUNTER_FOR_PERSONALIZED_GREETINGS + ".*", - valueMatcher(GreetService.COUNTER_FOR_PERSONALIZED_GREETINGS,"", "total"), - ">> end of output >>"); - assertLinesMatch(expected, returnedLines, GreetService.TIMER_FOR_GETS + "_seconds_max TYPE and value"); - } - } - - private static String valueMatcher(String meterName, String unit, String statName) { - // counterForPersonalizedGreetings_total{scope="application"} 1.0 # {span_id="41d2a1755a2b8797",trace_id="41d2a1755a2b8797"} 1.0 1696888732.920 - return meterName - + (unit == null || unit.isBlank() ? "" : "_" + unit) - + "_" + statName + ".*? # .*?trace_id=\"[^\"]+\"\\} [\\d\\.]+ [\\d\\.]+"; - } - -} diff --git a/examples/metrics/filtering/mp/README.md b/examples/metrics/filtering/mp/README.md deleted file mode 100644 index fb4fa520d85..00000000000 --- a/examples/metrics/filtering/mp/README.md +++ /dev/null @@ -1,47 +0,0 @@ -# Helidon Metrics Filtering MP Example - -This project implements a simple Hello World REST service using Helidon SE and demonstrates the -optional metrics exemplar support. - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-metrics-filtering-mp.jar -``` - -## Exercise the application - -```shell -curl -X GET http://localhost:8080/greet -#Output: {"message":"Hello World!"} - -curl -X GET http://localhost:8080/greet/Joe -#Output: {"message":"Hello Joe!"} - -curl -X PUT -H "Content-Type: application/json" -d '{"message" : "Hola"}' http://localhost:8080/greet/greeting - -curl -X GET http://localhost:8080/greet/Jose -#Output: {"message":"Hola Jose!"} - -curl -X GET http://localhost:8080/greet -#Output: {"message":"Hola World!"} -``` - -## Retrieve application metrics - -```shell -# Prometheus format with exemplars - -curl -s -X GET http://localhost:8080/metrics/application -``` -``` -# TYPE application_counterForPersonalizedGreetings_total counter -# HELP application_counterForPersonalizedGreetings_total -application_counterForPersonalizedGreetings_total 2 # {trace_id="78e61eed351f4c9d"} 1 1617812495.016000 -. . . -# TYPE application_timerForGets_mean_seconds gauge -application_timerForGets_mean_seconds 0.005772598385062112 # {trace_id="b22f13c37ba8b879"} 0.001563945 1617812578.687000 -# TYPE application_timerForGets_max_seconds gauge -application_timerForGets_max_seconds 0.028018165 # {trace_id="a1b127002725143c"} 0.028018165 1617812467.524000 -``` diff --git a/examples/metrics/filtering/mp/pom.xml b/examples/metrics/filtering/mp/pom.xml deleted file mode 100644 index 0cc67b6df4f..00000000000 --- a/examples/metrics/filtering/mp/pom.xml +++ /dev/null @@ -1,109 +0,0 @@ - - - - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../../applications/mp/pom.xml - - 4.0.0 - - io.helidon.examples.metrics.filtering - helidon-examples-metrics-filtering-mp - Helidon Examples Metrics MP Filtering - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.microprofile.metrics - helidon-microprofile-metrics - - - io.helidon.webserver.observe - helidon-webserver-observe-metrics - runtime - - - io.helidon.metrics - helidon-metrics-system-meters - runtime - - - io.helidon.logging - helidon-logging-jul - runtime - - - io.helidon.webclient - helidon-webclient - test - - - io.helidon.microprofile.testing - helidon-microprofile-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - check-for-inflight-with-config-settings - - test - - - - true - - - - - - - - diff --git a/examples/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/GreetResource.java b/examples/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/GreetResource.java deleted file mode 100644 index 53422776139..00000000000 --- a/examples/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/GreetResource.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.metrics.filtering.mp; - -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.metrics.annotation.Counted; -import org.eclipse.microprofile.metrics.annotation.Timed; - -/** - * A simple JAX-RS resource to greet you with filtered metrics support. - */ -@Path("/greet") -@RequestScoped -public class GreetResource { - - static final String TIMER_FOR_GETS = "timerForGets"; - static final String COUNTER_FOR_PERSONALIZED_GREETINGS = "counterForPersonalizedGreetings"; - - /** - * 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 jakarta.json.JsonObject} - */ - @GET - @Produces(MediaType.APPLICATION_JSON) - @Timed(name = TIMER_FOR_GETS, absolute = true) - public GreetingMessage getDefaultMessage() { - return createResponse("World"); - } - - /** - * Return a greeting message using the name that was provided. - * - * @param name the name to greet - * @return {@link jakarta.json.JsonObject} - */ - @Path("/{name}") - @GET - @Produces(MediaType.APPLICATION_JSON) - @Timed(name = TIMER_FOR_GETS, absolute = true) - public GreetingMessage getMessage(@PathParam("name") String name) { - return createResponse(name); - } - - /** - * Set the greeting to use in future messages. - * - * @param message JSON containing the new greeting - * @return {@link Response} - */ - @Path("/greeting") - @PUT - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @Counted(name = COUNTER_FOR_PERSONALIZED_GREETINGS, absolute = true) - public Response updateGreeting(GreetingMessage message) { - if (message.getMessage() == null) { - GreetingMessage entity = new GreetingMessage("No greeting provided"); - return Response.status(Response.Status.BAD_REQUEST).entity(entity).build(); - } - - greetingProvider.setMessage(message.getMessage()); - return Response.status(Response.Status.NO_CONTENT).build(); - } - - private GreetingMessage createResponse(String who) { - String msg = String.format("%s %s!", greetingProvider.getMessage(), who); - - return new GreetingMessage(msg); - } -} diff --git a/examples/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/GreetingMessage.java b/examples/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/GreetingMessage.java deleted file mode 100644 index e0b889165e9..00000000000 --- a/examples/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/GreetingMessage.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2023 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.metrics.filtering.mp; - -/** - * POJO defining the greeting message content. - */ -@SuppressWarnings("unused") -public class GreetingMessage { - private String message; - - /** - * Create a new GreetingMessage instance. - */ - public GreetingMessage() { - } - - /** - * Create a new GreetingMessage instance. - * - * @param message message - */ - public GreetingMessage(String message) { - this.message = message; - } - - /** - * Gets the message value. - * - * @return message value - */ - public String getMessage() { - return message; - } - - /** - * Sets the message value. - * - * @param message message value to set - */ - public void setMessage(String message) { - this.message = message; - } -} diff --git a/examples/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/GreetingProvider.java b/examples/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/GreetingProvider.java deleted file mode 100644 index fff218cf5e3..00000000000 --- a/examples/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/GreetingProvider.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2021 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.metrics.filtering.mp; - -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/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/package-info.java b/examples/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/package-info.java deleted file mode 100644 index 8b9fae9f18a..00000000000 --- a/examples/metrics/filtering/mp/src/main/java/io/helidon/examples/metrics/filtering/mp/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 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. - */ - -/** - * Helidon MicroProfile metrics filtering example. - */ -package io.helidon.examples.metrics.filtering.mp; diff --git a/examples/metrics/filtering/mp/src/main/resources/META-INF/beans.xml b/examples/metrics/filtering/mp/src/main/resources/META-INF/beans.xml deleted file mode 100644 index dbf3e648c1e..00000000000 --- a/examples/metrics/filtering/mp/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/metrics/filtering/mp/src/main/resources/META-INF/microprofile-config.properties b/examples/metrics/filtering/mp/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index d652c78f17b..00000000000 --- a/examples/metrics/filtering/mp/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2021, 2023 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. -# -app.greeting=Hello - -# Override configuration to use a random port for the unit tests -config_ordinal=1000 -# Microprofile server properties -server.port=8080 -server.host=0.0.0.0 - -metrics.scoping.scopes.0.name=application -metrics.scoping.scopes.0.filter.exclude = .*Gets diff --git a/examples/metrics/filtering/mp/src/main/resources/logging.properties b/examples/metrics/filtering/mp/src/main/resources/logging.properties deleted file mode 100644 index af98f91f1ba..00000000000 --- a/examples/metrics/filtering/mp/src/main/resources/logging.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright (c) 2021, 2023 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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.cors.level=INFO diff --git a/examples/metrics/filtering/mp/src/test/java/io/helidon/examples/metrics/filtering/mp/MainTest.java b/examples/metrics/filtering/mp/src/test/java/io/helidon/examples/metrics/filtering/mp/MainTest.java deleted file mode 100644 index 12fb0ad03b9..00000000000 --- a/examples/metrics/filtering/mp/src/test/java/io/helidon/examples/metrics/filtering/mp/MainTest.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.metrics.filtering.mp; - -import java.time.Duration; - -import io.helidon.microprofile.testing.junit5.HelidonTest; - -import jakarta.inject.Inject; -import org.eclipse.microprofile.metrics.Counter; -import org.eclipse.microprofile.metrics.MetricRegistry; -import org.eclipse.microprofile.metrics.Timer; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - -@HelidonTest -public class MainTest { - - @Inject - private MetricRegistry appRegistry; - - @Test - void checkEnabledMetric() { - Counter personalizedGreetingsCounter = appRegistry.counter(GreetResource.COUNTER_FOR_PERSONALIZED_GREETINGS); - long before = personalizedGreetingsCounter.getCount(); - personalizedGreetingsCounter.inc(); - assertThat("Enabled counter value change", - personalizedGreetingsCounter.getCount() - before, is(1L)); - } - - @Test - void checkDisabledMetric() { - Timer getsTimer = appRegistry.timer(GreetResource.TIMER_FOR_GETS); - long before = getsTimer.getCount(); - getsTimer.update(Duration.ofSeconds(1)); - assertThat("Disabled timer value change", - getsTimer.getCount() - before, - is(0L)); - } -} diff --git a/examples/metrics/filtering/pom.xml b/examples/metrics/filtering/pom.xml deleted file mode 100644 index a9b2ca4eaa5..00000000000 --- a/examples/metrics/filtering/pom.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - helidon-examples-metrics-project - io.helidon.examples - 4.1.0-SNAPSHOT - - 4.0.0 - pom - - helidon-examples-metrics-filtering - Helidon Examples Metrics Filtering - - - se - mp - - diff --git a/examples/metrics/filtering/se/README.md b/examples/metrics/filtering/se/README.md deleted file mode 100644 index bbbd3ebab5d..00000000000 --- a/examples/metrics/filtering/se/README.md +++ /dev/null @@ -1,47 +0,0 @@ -# Helidon Filtering Metrics SE Example - -This project implements a simple Hello World REST service using Helidon SE and demonstrates the -optional metrics exemplar support. - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-metrics-se.jar -``` - -## Exercise the application - -```shell -curl -X GET http://localhost:8080/greet -#Output: {"message":"Hello World!"} - -curl -X GET http://localhost:8080/greet/Joe -#Output: {"message":"Hello Joe!"} - -curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}' http://localhost:8080/greet/greeting - -curl -X GET http://localhost:8080/greet/Jose -#Output: {"message":"Hola Jose!"} - -curl -X GET http://localhost:8080/greet -#Output: {"message":"Hola World!"} -``` - -## Retrieve application metrics - -```shell -# Prometheus format with exemplars - -curl -s -X GET http://localhost:8080/observe/metrics/application -``` -``` -# TYPE application_counterForPersonalizedGreetings_total counter -# HELP application_counterForPersonalizedGreetings_total -application_counterForPersonalizedGreetings_total 2 # {trace_id="78e61eed351f4c9d"} 1 1617812495.016000 -. . . -# TYPE application_timerForGets_mean_seconds gauge -application_timerForGets_mean_seconds 0.005772598385062112 # {trace_id="b22f13c37ba8b879"} 0.001563945 1617812578.687000 -# TYPE application_timerForGets_max_seconds gauge -application_timerForGets_max_seconds 0.028018165 # {trace_id="a1b127002725143c"} 0.028018165 1617812467.524000 -``` \ No newline at end of file diff --git a/examples/metrics/filtering/se/pom.xml b/examples/metrics/filtering/se/pom.xml deleted file mode 100644 index 14e6d683f0f..00000000000 --- a/examples/metrics/filtering/se/pom.xml +++ /dev/null @@ -1,117 +0,0 @@ - - - - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../../applications/se/pom.xml - - 4.0.0 - - io.helidon.examples.metrics.filtering - helidon-examples-metrics-se - Helidon Examples Metrics SE Filtering - - io.helidon.examples.metrics.filtering.se.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.http.media - helidon-http-media-jsonp - - - io.helidon.webserver.observe - helidon-webserver-observe - - - io.helidon.webserver.observe - helidon-webserver-observe-metrics - - - io.helidon.webserver.observe - helidon-webserver-observe-health - - - io.helidon.metrics - helidon-metrics-api - - - io.helidon.config - helidon-config-yaml - - - io.helidon.logging - helidon-logging-jul - runtime - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - check-for-inflight-with-config-settings - - test - - - - true - - - - - - - - diff --git a/examples/metrics/filtering/se/src/main/java/io/helidon/examples/metrics/filtering/se/GreetService.java b/examples/metrics/filtering/se/src/main/java/io/helidon/examples/metrics/filtering/se/GreetService.java deleted file mode 100644 index abb684e9584..00000000000 --- a/examples/metrics/filtering/se/src/main/java/io/helidon/examples/metrics/filtering/se/GreetService.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.metrics.filtering.se; - -import java.util.Collections; -import java.util.concurrent.atomic.AtomicReference; - -import io.helidon.config.Config; -import io.helidon.http.Status; -import io.helidon.metrics.api.Counter; -import io.helidon.metrics.api.MeterRegistry; -import io.helidon.metrics.api.Timer; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; - -/** - * 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 HttpService { - - /** - * The config value for the key {@code greeting}. - */ - private final AtomicReference greeting = new AtomicReference<>(); - - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - static final String TIMER_FOR_GETS = "timerForGets"; - static final String COUNTER_FOR_PERSONALIZED_GREETINGS = "counterForPersonalizedGreetings"; - - private final Timer timerForGets; - private final Counter personalizedGreetingsCounter; - - GreetService(MeterRegistry meterRegistry) { - Config config = Config.global(); - greeting.set(config.get("app.greeting").asString().orElse("Ciao")); - timerForGets = meterRegistry.getOrCreate(Timer.builder(TIMER_FOR_GETS)); - personalizedGreetingsCounter = meterRegistry.getOrCreate(Counter.builder(COUNTER_FOR_PERSONALIZED_GREETINGS)); - } - - /** - * A service registers itself by updating the routing rules. - * - * @param rules the routing rules. - */ - @Override - public void routing(HttpRules rules) { - rules.get("/", this::timeGet) - .get("/{name}", this::countPersonalized, 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().pathParameters().get("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 void updateGreetingFromJson(JsonObject jo, ServerResponse response) { - - if (!jo.containsKey("greeting")) { - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "No greeting provided") - .build(); - response.status(Status.BAD_REQUEST_400) - .send(jsonErrorObject); - return; - } - - greeting.set(jo.getString("greeting")); - response.status(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) { - JsonObject jsonObject = request.content().as(JsonObject.class); - updateGreetingFromJson(jsonObject, response); - } - - private void timeGet(ServerRequest request, ServerResponse response) { - timerForGets.record(() -> getDefaultMessageHandler(request, response)); - } - - private void countPersonalized(ServerRequest request, ServerResponse response) { - personalizedGreetingsCounter.increment(); - response.next(); - } -} diff --git a/examples/metrics/filtering/se/src/main/java/io/helidon/examples/metrics/filtering/se/Main.java b/examples/metrics/filtering/se/src/main/java/io/helidon/examples/metrics/filtering/se/Main.java deleted file mode 100644 index 08f408e6249..00000000000 --- a/examples/metrics/filtering/se/src/main/java/io/helidon/examples/metrics/filtering/se/Main.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.metrics.filtering.se; - -import java.util.regex.Pattern; - -import io.helidon.config.Config; -import io.helidon.logging.common.LogConfig; -import io.helidon.metrics.api.Meter; -import io.helidon.metrics.api.MeterRegistry; -import io.helidon.metrics.api.MetricsConfig; -import io.helidon.metrics.api.MetricsFactory; -import io.helidon.metrics.api.ScopeConfig; -import io.helidon.metrics.api.ScopingConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.http.HttpRouting; -import io.helidon.webserver.observe.ObserveFeature; -import io.helidon.webserver.observe.metrics.MetricsObserver; - -/** - * 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) { - WebServerConfig.Builder builder = WebServer.builder(); - setup(builder); - WebServer server = builder.build().start(); - System.out.println("WEB server is up! http://localhost:" + server.port() + "/greet"); - } - - /** - * Set up the server. - * - * @param server server builder - */ - static void setup(WebServerConfig.Builder server) { - - // load logging configuration - LogConfig.configureRuntime(); - - // By default, this will pick up application.yaml from the classpath - Config config = Config.create(); - Config.global(config); - - // Programmatically (not through config), tell the metrics feature to ignore the "gets" timer. - // To do so, create the scope config, then add it to the metrics config that ultimately - // the metrics feature class will use. - ScopeConfig scopeConfig = ScopeConfig.builder() - .name(Meter.Scope.APPLICATION) - .exclude(Pattern.compile(GreetService.TIMER_FOR_GETS)) - .build(); - - MetricsConfig initialMetricsConfig = config.get(MetricsConfig.METRICS_CONFIG_KEY) - .map(MetricsConfig::create) - .orElseGet(MetricsConfig::create); - MetricsConfig.Builder metricsConfigBuilder = MetricsConfig.builder(initialMetricsConfig) - .scoping(ScopingConfig.builder() - .putScope(Meter.Scope.APPLICATION, scopeConfig)); - - MeterRegistry meterRegistry = MetricsFactory.getInstance(config).globalRegistry(metricsConfigBuilder.build()); - - MetricsObserver metrics = MetricsObserver.builder() - .meterRegistry(meterRegistry) - .metricsConfig(metricsConfigBuilder) - .build(); - - server.featuresDiscoverServices(false) - .addFeature(ObserveFeature.just(metrics)) - .config(config.get("server")) - .routing(r -> routing(r, meterRegistry)); - } - - /** - * Set up routing. - * - * @param routing routing builder - */ - static void routing(HttpRouting.Builder routing, MeterRegistry meterRegistry) { - GreetService greetService = new GreetService(meterRegistry); - - routing.register("/greet", greetService); - } -} diff --git a/examples/metrics/filtering/se/src/main/java/io/helidon/examples/metrics/filtering/se/package-info.java b/examples/metrics/filtering/se/src/main/java/io/helidon/examples/metrics/filtering/se/package-info.java deleted file mode 100644 index 8b75421b62e..00000000000 --- a/examples/metrics/filtering/se/src/main/java/io/helidon/examples/metrics/filtering/se/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2021 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. - */ -/** - * Helidon SE example of controlling metrics using filtering. - */ -package io.helidon.examples.metrics.filtering.se; diff --git a/examples/metrics/filtering/se/src/main/resources/application.yaml b/examples/metrics/filtering/se/src/main/resources/application.yaml deleted file mode 100644 index 3388831856d..00000000000 --- a/examples/metrics/filtering/se/src/main/resources/application.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2021, 2023 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. -# - -app: - greeting: "Hello" - -server: - port: 8080 - host: 0.0.0.0 - -tracing: - service: "hello-world" diff --git a/examples/metrics/filtering/se/src/main/resources/logging.properties b/examples/metrics/filtering/se/src/main/resources/logging.properties deleted file mode 100644 index c916a0505a0..00000000000 --- a/examples/metrics/filtering/se/src/main/resources/logging.properties +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright (c) 2021, 2024 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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 diff --git a/examples/metrics/filtering/se/src/test/java/io/helidon/examples/metrics/filtering/se/MainTest.java b/examples/metrics/filtering/se/src/test/java/io/helidon/examples/metrics/filtering/se/MainTest.java deleted file mode 100644 index f21b6f51400..00000000000 --- a/examples/metrics/filtering/se/src/test/java/io/helidon/examples/metrics/filtering/se/MainTest.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.metrics.filtering.se; - -import java.util.Collections; - -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.WebServerConfig; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import org.hamcrest.CoreMatchers; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.not; - -@ServerTest -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 final Http1Client client; - - public MainTest(Http1Client client) { - this.client = client; - } - - @SetUpServer - public static void setup(WebServerConfig.Builder server) { - Main.setup(server); - } - - @Test - public void testHelloWorld() { - try (Http1ClientResponse response = client.get("/greet").request()) { - assertThat(response.as(JsonObject.class).getString("message"), CoreMatchers.is("Hello World!")); - } - - try (Http1ClientResponse response = client.get("/greet/Joe").request()) { - assertThat(response.as(JsonObject.class).getString("message"), CoreMatchers.is("Hello Joe!")); - } - - try (Http1ClientResponse response = client.put("/greet/greeting").submit(TEST_JSON_OBJECT)) { - assertThat(response.status().code(), CoreMatchers.is(204)); - } - - try (Http1ClientResponse response = client.get("/greet/Joe").request()) { - assertThat(response.as(JsonObject.class).getString("message"), CoreMatchers.is("Hola Joe!")); - } - - try (Http1ClientResponse response = client.get("/observe/metrics").request()) { - assertThat(response.status().code(), CoreMatchers.is(200)); - } - } - - @Test - public void testMetrics() { - try (Http1ClientResponse response = client.get("/greet").request()) { - assertThat(response.as(String.class), containsString("Hello World!")); - } - - try (Http1ClientResponse response = client.get("/greet/Joe").request()) { - assertThat(response.as(String.class), containsString("Hello Joe!")); - } - - try (Http1ClientResponse response = client.get("/observe/metrics/application").request()) { - String openMetricsOutput = response.as(String.class); - assertThat("Metrics output", openMetricsOutput, not(containsString(GreetService.TIMER_FOR_GETS))); - assertThat("Metrics output", openMetricsOutput, containsString(GreetService.COUNTER_FOR_PERSONALIZED_GREETINGS)); - } - } -} diff --git a/examples/metrics/http-status-count-se/README.md b/examples/metrics/http-status-count-se/README.md deleted file mode 100644 index e660e3832e3..00000000000 --- a/examples/metrics/http-status-count-se/README.md +++ /dev/null @@ -1,101 +0,0 @@ -# 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 - - -```shell -mvn package -java -jar target/http-status-count-se.jar -``` - -## Exercise the application -```shell -curl -X GET http://localhost:8080/simple-greet -``` -```listing -{"message":"Hello World!"} -``` - -```shell -curl -X GET http://localhost:8080/greet -``` -```listing -{"message":"Hello World!"} -``` -```shell -curl -X GET http://localhost:8080/greet/Joe -``` -```listing -{"message":"Hello Joe!"} -``` -```shell -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 -```shell -# Prometheus Format -curl -s -X GET http://localhost:8080/observe/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 - -```shell -curl -H "Accept: application/json" -X GET http://localhost:8080/observe/metrics -``` -```json -{ -... - "httpStatus;range=1xx": 0, - "httpStatus;range=2xx": 5, - "httpStatus;range=3xx": 0, - "httpStatus;range=4xx": 0, - "httpStatus;range=5xx": 0, -... -``` - -## Try health - -```shell -curl -s -X GET http://localhost:8080/health -``` -```listing -{"outcome":"UP",... - -``` diff --git a/examples/metrics/http-status-count-se/pom.xml b/examples/metrics/http-status-count-se/pom.xml deleted file mode 100644 index c32e3f075ab..00000000000 --- a/examples/metrics/http-status-count-se/pom.xml +++ /dev/null @@ -1,113 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples - http-status-count-se - 1.0-SNAPSHOT - - Helidon Examples Metrics HTTP Status Counters - - - io.helidon.examples.se.httpstatuscount.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.config - helidon-config-yaml - - - io.helidon.metrics - helidon-metrics-api - - - io.helidon.webserver.observe - helidon-webserver-observe - - - io.helidon.webserver.observe - helidon-webserver-observe-metrics - - - io.helidon.metrics - helidon-metrics-system-meters - runtime - - - io.helidon.logging - helidon-logging-jul - runtime - - - io.helidon.webserver.observe - helidon-webserver-observe-health - - - io.helidon.health - helidon-health-checks - - - io.helidon.http.media - helidon-http-media-jsonp - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - 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 deleted file mode 100644 index 9484e4691b2..00000000000 --- a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/GreetService.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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; -import java.util.concurrent.atomic.AtomicReference; - -import io.helidon.config.Config; -import io.helidon.http.Status; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; - -/** - * 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 HttpService { - - /** - * The config value for the key {@code greeting}. - */ - private final AtomicReference greeting = new AtomicReference<>(); - - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - GreetService() { - Config config = Config.global(); - 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 routing(HttpRules 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().pathParameters().get("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 void updateGreetingFromJson(JsonObject jo, ServerResponse response) { - if (!jo.containsKey("greeting")) { - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "No greeting provided") - .build(); - response.status(Status.BAD_REQUEST_400) - .send(jsonErrorObject); - return; - } - - greeting.set(jo.getString("greeting")); - response.status(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) { - JsonObject jsonObject = request.content().as(JsonObject.class); - updateGreetingFromJson(jsonObject, 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 deleted file mode 100644 index 0260f88728c..00000000000 --- a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/HttpStatusMetricService.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.Set; -import java.util.concurrent.atomic.AtomicInteger; - -import io.helidon.metrics.api.Counter; -import io.helidon.metrics.api.MeterRegistry; -import io.helidon.metrics.api.Metrics; -import io.helidon.metrics.api.Tag; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -/** - * 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 io.helidon.metrics.api.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 HttpService { - - static final String STATUS_COUNTER_NAME = "httpStatus"; - - static final String STATUS_TAG_NAME = "range"; - - private static final String COUNTER_DESCR = "Counts the number of HTTP responses in each status category (1xx, 2xx, etc.)"; - - private static final AtomicInteger IN_PROGRESS = new AtomicInteger(); - - private final Counter[] responseCounters = new Counter[6]; - - static HttpStatusMetricService create() { - return new HttpStatusMetricService(); - } - - private HttpStatusMetricService() { - MeterRegistry registry = Metrics.globalRegistry(); - - // Declare the counters and keep references to them. - for (int i = 1; i < responseCounters.length; i++) { - - responseCounters[i] = registry.getOrCreate(Counter.builder(STATUS_COUNTER_NAME) - .tags(Set.of(Tag.create(STATUS_TAG_NAME, i + "xx"))) - .description(COUNTER_DESCR)); - } - } - - @Override - public void routing(HttpRules rules) { - rules.any(this::updateRange); - } - - // for testing - static boolean isInProgress() { - return IN_PROGRESS.get() != 0; - } - - private void updateRange(ServerRequest request, ServerResponse response) { - IN_PROGRESS.incrementAndGet(); - response.whenSent(() -> logMetric(response)); - response.next(); - } - - private void logMetric(ServerResponse response) { - int range = response.status().code() / 100; - if (range > 0 && range < responseCounters.length) { - responseCounters[range].increment(); - } - IN_PROGRESS.decrementAndGet(); - } -} 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 deleted file mode 100644 index fa2516d8012..00000000000 --- a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/Main.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.config.Config; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.http.HttpRouting; - -/** - * 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) { - WebServerConfig.Builder builder = WebServer.builder(); - setup(builder); - WebServer server = builder.build().start(); - System.out.println("WEB server is up! http://localhost:" + server.port() + "/greet"); - } - - /** - * Set up the server. - * - * @param server server builder - */ - static void setup(WebServerConfig.Builder server) { - // load logging configuration - LogConfig.configureRuntime(); - - // By default, this will pick up application.yaml from the classpath - Config config = Config.create(); - Config.global(config); - - server.routing(Main::routing) - .config(config.get("server")); - - } - - /** - * Set up routing. - * - * @param routing routing builder - */ - static void routing(HttpRouting.Builder routing) { - routing.register(HttpStatusMetricService.create()) // no endpoint, just metrics updates - .register("/simple-greet", new SimpleGreetService()) - .register("/greet", new GreetService()); - } -} 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 deleted file mode 100644 index 0b8aa40e92c..00000000000 --- a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/SimpleGreetService.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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; -import java.util.logging.Logger; - -import io.helidon.config.Config; -import io.helidon.metrics.api.Counter; -import io.helidon.metrics.api.MeterRegistry; -import io.helidon.metrics.api.Metrics; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; - -/** - * 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 HttpService { - - private static final Logger LOGGER = Logger.getLogger(SimpleGreetService.class.getName()); - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - private final MeterRegistry registry = Metrics.globalRegistry(); - private final Counter accessCtr = registry.getOrCreate(Counter.builder("accessctr")); - - private final String greeting; - - SimpleGreetService() { - Config config = Config.global(); - 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 routing(HttpRules 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.increment(); - response.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 deleted file mode 100644 index d5b622ea310..00000000000 --- a/examples/metrics/http-status-count-se/src/main/java/io/helidon/examples/se/httpstatuscount/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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.se.httpstatuscount; 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 deleted file mode 100644 index d756e942feb..00000000000 --- a/examples/metrics/http-status-count-se/src/main/resources/application.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) 2022, 2023 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 - -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 deleted file mode 100644 index bf3401a8c86..00000000000 --- a/examples/metrics/http-status-count-se/src/main/resources/logging.properties +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright (c) 2022, 2024 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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 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 deleted file mode 100644 index 4e8a60dc7f6..00000000000 --- a/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/MainTest.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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; - -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.WebServerConfig; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.is; - -@TestMethodOrder(MethodOrderer.MethodName.class) -@ServerTest -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 final Http1Client client; - - public MainTest(Http1Client client) { - this.client = client; - } - - @SetUpServer - public static void setup(WebServerConfig.Builder server) { - Main.setup(server); - } - - @Test - public void testMicroprofileMetrics() { - try (Http1ClientResponse response = client.get("/simple-greet/greet-count").request()) { - assertThat(response.as(String.class), containsString("Hello World!")); - } - - try (Http1ClientResponse response = client.get("/observe/metrics").request()) { - assertThat("Metrics output", response.as(String.class), containsString("accessctr_total")); - } - } - - @Test - public void testMetrics() { - try (Http1ClientResponse response = client.get("/observe/metrics").request()) { - assertThat(response.status().code(), is(200)); - } - } - - @Test - public void testHealth() { - try (Http1ClientResponse response = client.get("/observe/health").request()) { - assertThat(response.status().code(), is(204)); - } - } - - @Test - public void testSimpleGreet() { - try (Http1ClientResponse response = client.get("/simple-greet").request()) { - assertThat(response.as(JsonObject.class).getString("message"), is("Hello World!")); - } - } - - @Test - public void testGreetings() { - try (Http1ClientResponse response = client.get("/greet/Joe").request()) { - assertThat(response.as(JsonObject.class).getString("message"), is("Hello Joe!")); - } - - try (Http1ClientResponse response = client.put("/greet/greeting").submit(TEST_JSON_OBJECT)) { - assertThat(response.status().code(), is(204)); - } - - try (Http1ClientResponse response = client.get("/greet/Joe").request()) { - assertThat(response.as(JsonObject.class).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 deleted file mode 100644 index c4fce31acab..00000000000 --- a/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/StatusService.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2022, 2024 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.http.Status; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -/** - * 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 HttpService { - - @Override - public void routing(HttpRules rules) { - rules.get("/{status}", this::respondWithRequestedStatus); - } - - private void respondWithRequestedStatus(ServerRequest request, ServerResponse response) { - String statusText = request.path().pathParameters().get("status"); - int status; - String msg; - try { - status = Integer.parseInt(statusText); - msg = "Successful conversion"; - } catch (NumberFormatException ex) { - status = Status.INTERNAL_SERVER_ERROR_500.code(); - msg = "Unsuccessful conversion"; - } - Status httpStatus = Status.create(status); - response.status(status); - if (httpStatus != Status.NO_CONTENT_204) { - response.send(msg); - } else { - response.send(); - } - } -} 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 deleted file mode 100644 index 840b7c90d27..00000000000 --- a/examples/metrics/http-status-count-se/src/test/java/io/helidon/examples/se/httpstatuscount/StatusTest.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.Set; - -import io.helidon.common.media.type.MediaTypes; -import io.helidon.config.Config; -import io.helidon.http.Status; -import io.helidon.metrics.api.Counter; -import io.helidon.metrics.api.MeterRegistry; -import io.helidon.metrics.api.Metrics; -import io.helidon.metrics.api.Tag; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static io.helidon.examples.se.httpstatuscount.HttpStatusMetricService.STATUS_COUNTER_NAME; -import static io.helidon.examples.se.httpstatuscount.HttpStatusMetricService.STATUS_TAG_NAME; -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.isEmptyString; -import static org.junit.jupiter.api.Assertions.fail; - -@ServerTest -public class StatusTest { - - private final Counter[] STATUS_COUNTERS = new Counter[6]; - private final Http1Client client; - - public StatusTest(Http1Client client) { - this.client = client; - } - - @SetUpServer - public static void setup(WebServerConfig.Builder server) { - Config.global(Config.create()); - server.routing(r -> { - Main.routing(r); - r.register("/status", new StatusService()); - }); - } - - @BeforeEach - void findStatusMetrics() { - MeterRegistry meterRegistry = Metrics.globalRegistry(); - for (int i = 1; i < STATUS_COUNTERS.length; i++) { - STATUS_COUNTERS[i] = meterRegistry.getOrCreate(Counter.builder(STATUS_COUNTER_NAME) - .tags(Set.of(Tag.create(STATUS_TAG_NAME, i + "xx")))); - } - } - - @Test - void checkStatusMetrics() throws InterruptedException { - checkAfterStatus(Status.create(171)); - checkAfterStatus(Status.OK_200); - checkAfterStatus(Status.CREATED_201); - checkAfterStatus(Status.NO_CONTENT_204); - checkAfterStatus(Status.MOVED_PERMANENTLY_301); - checkAfterStatus(Status.UNAUTHORIZED_401); - checkAfterStatus(Status.NOT_FOUND_404); - } - - @Test - void checkStatusAfterGreet() throws InterruptedException { - long[] before = new long[6]; - for (int i = 1; i < 6; i++) { - before[i] = STATUS_COUNTERS[i].count(); - } - try (Http1ClientResponse response = client.get("/greet") - .accept(MediaTypes.APPLICATION_JSON) - .request()) { - assertThat("Status of /greet", response.status(), is(Status.OK_200)); - String entity = response.as(String.class); - assertThat(entity, not(isEmptyString())); - checkCounters(response.status(), before); - } - } - - void checkAfterStatus(Status status) throws InterruptedException { - long[] before = new long[6]; - for (int i = 1; i < 6; i++) { - before[i] = STATUS_COUNTERS[i].count(); - } - try (Http1ClientResponse response = client.get("/status/" + status.code()) - .accept(MediaTypes.APPLICATION_JSON) - .followRedirects(false) - .request()) { - assertThat("Response status", response.status().code(), is(status.code())); - checkCounters(status, before); - } - } - - @SuppressWarnings("BusyWait") - private void checkCounters(Status status, long[] before) throws InterruptedException { - // Make sure the server has updated the counter(s). - long now = System.currentTimeMillis(); - - while (HttpStatusMetricService.isInProgress()) { - Thread.sleep(50); - if (System.currentTimeMillis() - now > 5000) { - fail("Timed out while waiting for monitoring to finish"); - } - } - - int family = status.code() / 100; - for (int i = 1; i < 6; i++) { - long expectedDiff = i == family ? 1 : 0; - assertThat("Diff in counter " + family + "xx", STATUS_COUNTERS[i].count() - 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 deleted file mode 100644 index d756e942feb..00000000000 --- a/examples/metrics/http-status-count-se/src/test/resources/application.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) 2022, 2023 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 - -app: - greeting: "Hello" diff --git a/examples/metrics/kpi/README.md b/examples/metrics/kpi/README.md deleted file mode 100644 index 6584578fb76..00000000000 --- a/examples/metrics/kpi/README.md +++ /dev/null @@ -1,125 +0,0 @@ -# Helidon Metrics Key Performance Indicators SE Example - -This project implements a simple Hello World REST service using Helidon SE and demonstrates -support in Helidon for extended key performance indicator (KPI) metrics. - -Your application can set up KPI metrics either programmatically or using configuration. -The `Main` class of this example shows both techniques, checking the system property `useConfig` to -determine -which to use. -You would typically write any given application to use only one of the approaches. - -## Build and run - -```shell -mvn package -``` -To use programmatic set-up: -```shell -java -jar target/helidon-examples-metrics-kpi.jar -``` -To use configuration: -```shell -java -DuseConfig=true -jar target/helidon-examples-metrics-kpi.jar -```` - -## Exercise the application - -```shell -curl -X GET http://localhost:8080/greet -#Output: {"message":"Hello World!"} - -curl -X GET http://localhost:8080/greet/Joe -#Output: {"message":"Hello Joe!"} - -curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}' http://localhost:8080/greet/greeting - -curl -X GET http://localhost:8080/greet/Jose -#Output: {"message":"Hola Jose!"} - -curl -X GET http://localhost:8080/greet -#Output: {"message":"Hola World!"} -``` - -## Retrieve vendor metrics with key performance indicators - -For brevity, the example output below shows only some of the KPI metrics. - -Note that, even though the `curl` commands above access `/greet` endpoints five times, -the -`load` and (not shown here) -`count` and -`meter` are `6` in the Prometheus output example and `7` in the JSON output example. -Further, the `inFlight` -current value is `1`. - -This is -because Helidon tallies -all -requests, even those -to Helidon-provided services such as `/metrics` and `/health`, in the KPI metrics. -The request -to retrieve the metrics is the one that is in flight, and it contributes to the KPI metrics just -as requests to application endpoints do. - -Further, the request to `/metrics` is still in progress when Helidon prepares the -output by getting the values of the KPI metrics at that moment. -If _that_ request turns out to be long- running, Helidon would discover so only -_after_ preparing the metrics output and completing the request. -The `longRunning` `Meter` -values in _that_ -response -could -not reflect the fact that Helidon would subsequently conclude that _that_ request was -long-running. - -## Prometheus format -```shell -curl -s -X GET http://localhost:8080/observe/metrics/vendor -``` -``` -... -# TYPE vendor_requests_inFlight_current concurrent gauge -# HELP vendor_requests_inFlight_current Measures the number of currently in-flight requests -vendor_requests_inFlight_current 1 -# TYPE vendor_requests_inFlight_min concurrent gauge -vendor_requests_inFlight_min 0 -# TYPE vendor_requests_inFlight_max concurrent gauge -vendor_requests_inFlight_max 1 -# TYPE vendor_requests_load_total counter -# HELP vendor_requests_load_total Measures the total number of in-flight requests and rates at which they occur -vendor_requests_load_total 6 -# TYPE vendor_requests_load_rate_per_second gauge -vendor_requests_load_rate_per_second 0.04932913209653636 -# TYPE vendor_requests_load_one_min_rate_per_second gauge -vendor_requests_load_one_min_rate_per_second 0.025499793037824785 -# TYPE vendor_requests_load_five_min_rate_per_second gauge -vendor_requests_load_five_min_rate_per_second 0.012963147773962286 -# TYPE vendor_requests_load_fifteen_min_rate_per_second gauge -vendor_requests_load_fifteen_min_rate_per_second 0.005104944851522425 -... -``` -## JSON output - - -```shell -curl -s -X GET -H "Accept: application/json" http://localhost:8080/observe/metrics/vendor -``` -``` -{ - ... - "requests.inFlight": { - "current": 1, - "max": 1, - "min": 0 - }, - "requests.load": { - "count": 7, - "meanRate": 0.01530869471741443, - "oneMinRate": 0.00016123154886115814, - "fiveMinRate": 0.005344110443653005, - "fifteenMinRate": 0.004286243527303867 - }, - ... -} -``` diff --git a/examples/metrics/kpi/pom.xml b/examples/metrics/kpi/pom.xml deleted file mode 100644 index f32ee3a7805..00000000000 --- a/examples/metrics/kpi/pom.xml +++ /dev/null @@ -1,119 +0,0 @@ - - - - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - 4.0.0 - - io.helidon.examples.metrics - helidon-examples-metrics-kpi - Helidon Examples Metrics Key Performance Indicators - - - io.helidon.examples.metrics.kpi.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.http.media - helidon-http-media-jsonp - - - io.helidon.webserver.observe - helidon-webserver-observe - - - io.helidon.webserver.observe - helidon-webserver-observe-metrics - - - io.helidon.metrics - helidon-metrics-system-meters - runtime - - - io.helidon.logging - helidon-logging-jul - runtime - - - io.helidon.metrics - helidon-metrics-trace-exemplar - - - io.helidon.config - helidon-config-yaml - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - check-for-inflight-with-config-settings - - test - - - - true - - - - - - - - diff --git a/examples/metrics/kpi/src/main/java/io/helidon/examples/metrics/kpi/GreetService.java b/examples/metrics/kpi/src/main/java/io/helidon/examples/metrics/kpi/GreetService.java deleted file mode 100644 index 6f8a92aeaf6..00000000000 --- a/examples/metrics/kpi/src/main/java/io/helidon/examples/metrics/kpi/GreetService.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.metrics.kpi; - -import java.util.Collections; -import java.util.concurrent.atomic.AtomicReference; - -import io.helidon.config.Config; -import io.helidon.http.Status; -import io.helidon.metrics.api.Counter; -import io.helidon.metrics.api.Meter; -import io.helidon.metrics.api.MeterRegistry; -import io.helidon.metrics.api.Metrics; -import io.helidon.metrics.api.Timer; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; - -/** - * 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 HttpService { - - /** - * The config value for the key {@code greeting}. - */ - private final AtomicReference greeting = new AtomicReference<>(); - - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - static final String TIMER_FOR_GETS = "timerForGets"; - static final String COUNTER_FOR_PERSONALIZED_GREETINGS = "counterForPersonalizedGreetings"; - - private final Timer timerForGets; - - private final Counter personalizedGreetingsCounter; - - GreetService() { - Config config = Config.global(); - greeting.set(config.get("app.greeting").asString().orElse("Ciao")); - MeterRegistry meterRegistry = Metrics.globalRegistry(); - timerForGets = meterRegistry.getOrCreate(Timer.builder(TIMER_FOR_GETS) - .baseUnit(Meter.BaseUnits.NANOSECONDS)); - personalizedGreetingsCounter = meterRegistry.getOrCreate(Counter.builder(COUNTER_FOR_PERSONALIZED_GREETINGS)); - } - - /** - * A service registers itself by updating the routing rules. - * - * @param rules the routing rules. - */ - @Override - public void routing(HttpRules rules) { - rules.get("/", this::timeGet, this::getDefaultMessageHandler) - .get("/{name}", this::countPersonalized, 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().pathParameters().get("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 void updateGreetingFromJson(JsonObject jo, ServerResponse response) { - - if (!jo.containsKey("greeting")) { - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "No greeting provided") - .build(); - response.status(Status.BAD_REQUEST_400) - .send(jsonErrorObject); - return; - } - - greeting.set(jo.getString("greeting")); - response.status(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) { - JsonObject jsonObject = request.content().as(JsonObject.class); - updateGreetingFromJson(jsonObject, response); - } - - private void timeGet(ServerRequest request, ServerResponse response) { - timerForGets.record((Runnable) response::next); - } - - private void countPersonalized(ServerRequest request, ServerResponse response) { - personalizedGreetingsCounter.increment(); - response.next(); - } -} diff --git a/examples/metrics/kpi/src/main/java/io/helidon/examples/metrics/kpi/Main.java b/examples/metrics/kpi/src/main/java/io/helidon/examples/metrics/kpi/Main.java deleted file mode 100644 index ffb44c5d1eb..00000000000 --- a/examples/metrics/kpi/src/main/java/io/helidon/examples/metrics/kpi/Main.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.metrics.kpi; - -import java.time.Duration; - -import io.helidon.config.Config; -import io.helidon.logging.common.LogConfig; -import io.helidon.metrics.api.KeyPerformanceIndicatorMetricsConfig; -import io.helidon.metrics.api.MetricsConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.http.HttpRouting; -import io.helidon.webserver.observe.ObserveFeature; -import io.helidon.webserver.observe.metrics.MetricsObserver; - -/** - * The application main class. - */ -public final class Main { - - static final String USE_CONFIG_PROPERTY_NAME = "useConfig"; - - static final boolean USE_CONFIG = Boolean.getBoolean(USE_CONFIG_PROPERTY_NAME); - - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * - * @param args command line arguments. - */ - public static void main(final String[] args) { - WebServerConfig.Builder builder = WebServer.builder(); - setup(builder); - WebServer server = builder.build().start(); - System.out.println("WEB server is up! http://localhost:" + server.port() + "/greet"); - } - - /** - * Set up the server. - * - * @param server server builder - */ - static void setup(WebServerConfig.Builder server) { - // load logging configuration - LogConfig.configureRuntime(); - - // By default, this will pick up application.yaml from the classpath - Config config = Config.create(); - Config.global(config); - - /* - * For purposes of illustration, the key performance indicator settings for the - * MetricsSupport instance are set up according to a system property, so you can see, - * in one example, how to code each approach. Normally, you would choose one - * approach to use in an application. - */ - MetricsObserver metricsObserver = USE_CONFIG - ? metricsSupportWithConfig(config.get("metrics")) - : metricsSupportWithoutConfig(); - - - server.addFeature(ObserveFeature.just(metricsObserver)) - .routing(Main::routing) - .config(config.get("server")); - - } - - /** - * Setup routing. - * - * @param routing routing builder - */ - private static void routing(HttpRouting.Builder routing) { - - routing.register("/greet", new GreetService()); - } - - /** - * Creates a {@link MetricsObserver} instance using a "metrics" configuration node. - * - * @param metricsConfig {@link Config} node with key "metrics" if present; an empty node otherwise - * @return {@code MetricsSupport} object with metrics (including KPI) set up using the config node - */ - private static MetricsObserver metricsSupportWithConfig(Config metricsConfig) { - return MetricsObserver.create(metricsConfig); - } - - /** - * Creates a {@link MetricsObserver} instance explicitly turning on extended KPI metrics. - * - * @return {@code MetricsSupport} object with extended KPI metrics enabled - */ - private static MetricsObserver metricsSupportWithoutConfig() { - KeyPerformanceIndicatorMetricsConfig.Builder configBuilder = - KeyPerformanceIndicatorMetricsConfig.builder() - .extended(true) - .longRunningRequestThreshold(Duration.ofSeconds(2)); - return MetricsObserver.builder() - .metricsConfig(MetricsConfig.builder() - .keyPerformanceIndicatorMetricsConfig(configBuilder)) - .build(); - } -} diff --git a/examples/metrics/kpi/src/main/java/io/helidon/examples/metrics/kpi/package-info.java b/examples/metrics/kpi/src/main/java/io/helidon/examples/metrics/kpi/package-info.java deleted file mode 100644 index 04a9b466633..00000000000 --- a/examples/metrics/kpi/src/main/java/io/helidon/examples/metrics/kpi/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2021 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. - */ - -/** - * Quickstart demo application for key performance metrics. - *

      - * Start with {@link io.helidon.examples.metrics.kpi.Main} class. - *

      - * @see io.helidon.examples.metrics.kpi.Main - */ -package io.helidon.examples.metrics.kpi; diff --git a/examples/metrics/kpi/src/main/resources/application.yaml b/examples/metrics/kpi/src/main/resources/application.yaml deleted file mode 100644 index a490db5db6f..00000000000 --- a/examples/metrics/kpi/src/main/resources/application.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2021, 2023 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. -# - -app: - greeting: "Hello" - -server: - port: 8080 - host: 0.0.0.0 - -metrics: - key-performance-indicators: - extended: true - long-running: - threshold-ms: 2000 # two seconds diff --git a/examples/metrics/kpi/src/main/resources/logging.properties b/examples/metrics/kpi/src/main/resources/logging.properties deleted file mode 100644 index c916a0505a0..00000000000 --- a/examples/metrics/kpi/src/main/resources/logging.properties +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright (c) 2021, 2024 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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 diff --git a/examples/metrics/kpi/src/test/java/io/helidon/examples/metrics/kpi/MainTest.java b/examples/metrics/kpi/src/test/java/io/helidon/examples/metrics/kpi/MainTest.java deleted file mode 100644 index fb40af1ced3..00000000000 --- a/examples/metrics/kpi/src/test/java/io/helidon/examples/metrics/kpi/MainTest.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.metrics.kpi; - -import java.util.Collections; - -import io.helidon.metrics.api.Meter; -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.WebServerConfig; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; - -@ServerTest -public class MainTest { - - private static final String KPI_REGISTRY_TYPE = Meter.Scope.VENDOR; - 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 final Http1Client client; - - public MainTest(Http1Client client) { - this.client = client; - } - - @SetUpServer - public static void setup(WebServerConfig.Builder server) { - Main.setup(server); - } - - @Test - public void testHelloWorld() { - try (Http1ClientResponse response = client.get("/greet").request()) { - assertThat(response.as(JsonObject.class).getString("message"), is("Hello World!")); - } - - try (Http1ClientResponse response = client.get("/greet/Joe").request()) { - assertThat(response.as(JsonObject.class).getString("message"), is("Hello Joe!")); - } - - try (Http1ClientResponse response = client.put("/greet/greeting").submit(TEST_JSON_OBJECT)) { - assertThat(response.status().code(), is(204)); - } - - try (Http1ClientResponse response = client.get("/greet/Joe").request()) { - assertThat(response.as(JsonObject.class).getString("message"), is("Hola Joe!")); - } - - try (Http1ClientResponse response = client.get("/observe/metrics").request()) { - assertThat(response.status().code(), is(200)); - } - } - - @Test - public void testMetrics() { - try (Http1ClientResponse response = client.get("/greet").request()) { - assertThat(response.as(String.class), containsString("Hello World!")); - } - - try (Http1ClientResponse response = client.get("/greet/Joe") - .request()) { - assertThat(response.as(String.class), containsString("Hello Joe!")); - } - - try (Http1ClientResponse response = client.get("/observe/metrics/" + KPI_REGISTRY_TYPE).request()) { - assertThat("Returned metrics output", response.as(String.class), - containsString("# TYPE " + "requests_inFlight")); - } - } -} diff --git a/examples/metrics/pom.xml b/examples/metrics/pom.xml deleted file mode 100644 index 2ee63177b59..00000000000 --- a/examples/metrics/pom.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - helidon-examples-project - io.helidon.examples - 4.1.0-SNAPSHOT - - 4.0.0 - pom - - helidon-examples-metrics-project - Helidon Examples Metrics - - - exemplar - kpi - filtering - http-status-count-se - - - diff --git a/examples/microprofile/README.md b/examples/microprofile/README.md deleted file mode 100644 index f678273b5c4..00000000000 --- a/examples/microprofile/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Helidon MP Examples - -This directory contains Helidon MP examples. diff --git a/examples/microprofile/bean-validation/README.md b/examples/microprofile/bean-validation/README.md deleted file mode 100644 index 0d6a80a35cb..00000000000 --- a/examples/microprofile/bean-validation/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# Helidon MP Bean Validation Example - -This example implements a simple Hello World REST service using MicroProfile demonstrating Bean Validation. - -## Usage - -To be able to use bean validation add the following dependency: - -```xml - - io.helidon.microprofile.bean-validation - helidon-microprofile-bean-validation - -``` - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-microprofile-bean-validation.jar -``` - -## Exercise the application - -```shell -curl -X GET http://localhost:8080/valid/test@test.com -#Output: {"Valid test@test.com!"} - -curl -X GET -I http://localhost:8080/valid/null - -``` -``` -HTTP/1.1 400 Bad Request -Content-Type: application/json -transfer-encoding: chunked -connection: keep-alive - - -``` \ No newline at end of file diff --git a/examples/microprofile/bean-validation/pom.xml b/examples/microprofile/bean-validation/pom.xml deleted file mode 100644 index cd42f002689..00000000000 --- a/examples/microprofile/bean-validation/pom.xml +++ /dev/null @@ -1,95 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.microprofile - helidon-examples-microprofile-bean-validation - Helidon Examples Bean Validation - - - - io.helidon.microprofile.bundles - helidon-microprofile-core - - - io.helidon.microprofile.bean-validation - helidon-microprofile-bean-validation - - - - io.helidon.logging - helidon-logging-jul - runtime - - - io.smallrye - jandex - runtime - true - - - - io.helidon.microprofile.testing - helidon-microprofile-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/microprofile/bean-validation/src/main/java/io/helidon/examples/microprofile/bean/validation/ValidEmailResource.java b/examples/microprofile/bean-validation/src/main/java/io/helidon/examples/microprofile/bean/validation/ValidEmailResource.java deleted file mode 100644 index a718da31a59..00000000000 --- a/examples/microprofile/bean-validation/src/main/java/io/helidon/examples/microprofile/bean/validation/ValidEmailResource.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.microprofile.bean.validation; - -import java.util.Collections; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import jakarta.validation.constraints.Email; -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; - - -/** - * A simple JAX-RS resource to validate email. - * Examples: - * - * Get valid response: - * curl -X GET http://localhost:8080/valid/e@mail.com - * - * Test failed response: - * curl -X GET http://localhost:8080/valid/email - */ -@Path("/valid") -@ApplicationScoped -public class ValidEmailResource { - - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - /** - * Return a greeting message using the name that was provided. - * - * @param email the name to validate - * @return {@link JsonObject} - */ - @Path("/{email}") - @GET - @Produces(MediaType.APPLICATION_JSON) - public JsonObject getMessage(@PathParam("email") @Email String email) { - return createResponse(email); - } - - - private JsonObject createResponse(String who) { - String msg = String.format("%s %s!", "Valid", who); - - return JSON.createObjectBuilder() - .add("message", msg) - .build(); - } -} diff --git a/examples/microprofile/bean-validation/src/main/java/io/helidon/examples/microprofile/bean/validation/package-info.java b/examples/microprofile/bean-validation/src/main/java/io/helidon/examples/microprofile/bean/validation/package-info.java deleted file mode 100644 index 655e1620c5f..00000000000 --- a/examples/microprofile/bean-validation/src/main/java/io/helidon/examples/microprofile/bean/validation/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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. - */ - -/** - * Bean Validation example. - */ -package io.helidon.examples.microprofile.bean.validation; diff --git a/examples/microprofile/bean-validation/src/main/resources/META-INF/beans.xml b/examples/microprofile/bean-validation/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 0de0bc4f151..00000000000 --- a/examples/microprofile/bean-validation/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/microprofile/bean-validation/src/main/resources/META-INF/microprofile-config.properties b/examples/microprofile/bean-validation/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 125e4f0f9fc..00000000000 --- a/examples/microprofile/bean-validation/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,19 +0,0 @@ -# -# 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. -# - -# Microprofile server properties -server.port=8080 -server.host=0.0.0.0 diff --git a/examples/microprofile/bean-validation/src/main/resources/logging.properties b/examples/microprofile/bean-validation/src/main/resources/logging.properties deleted file mode 100644 index b5e2c644b3d..00000000000 --- a/examples/microprofile/bean-validation/src/main/resources/logging.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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 diff --git a/examples/microprofile/bean-validation/src/test/java/io/helidon/tests/integration/bean/validation/TestValidationEndpoint.java b/examples/microprofile/bean-validation/src/test/java/io/helidon/tests/integration/bean/validation/TestValidationEndpoint.java deleted file mode 100644 index 237437f34c1..00000000000 --- a/examples/microprofile/bean-validation/src/test/java/io/helidon/tests/integration/bean/validation/TestValidationEndpoint.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.tests.integration.bean.validation; - -import io.helidon.microprofile.testing.junit5.HelidonTest; - -import jakarta.inject.Inject; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.Response; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * When enabled, endpoints with bean validation should return response with BAD REQUEST status. - */ -@HelidonTest -public class TestValidationEndpoint { - - @Inject - private WebTarget webTarget; - - - /** - * This Endpoint should always fail with BAD REQUEST, as bean validation fails with Not Null. - */ - @Test - public void testValidation() { - - Response.StatusType statusInfo = webTarget - .path("/valid/email") - .request() - .get() - .getStatusInfo(); - - assertThat("Endpoint should return BAD REQUEST", statusInfo.getStatusCode(), is(Response.Status.BAD_REQUEST.getStatusCode())); - - } - - /** - * This test should always work, since no validation is performed. - */ - @Test - public void testNormalUsage(){ - - Response.StatusType statusInfo = webTarget - .path("/valid/e@mail.com") - .request() - .get() - .getStatusInfo(); - assertThat("Endpoint should return OK", statusInfo.getStatusCode(), is(Response.Status.OK.getStatusCode())); - - } -} diff --git a/examples/microprofile/cors/README.md b/examples/microprofile/cors/README.md deleted file mode 100644 index 575d01933b7..00000000000 --- a/examples/microprofile/cors/README.md +++ /dev/null @@ -1,130 +0,0 @@ -# Helidon MP CORS Example - -This example shows a simple greeting application, similar to the one from the -Helidon MP QuickStart, enhanced with CORS support. - -Near the end of the `resources/logging.properties` file, a commented line would turn on `FINE` -logging that would reveal how the Helidon CORS support makes it decisions. To see that logging, -uncomment that line and then package and run the application. - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-microprofile-cors.jar -``` - -## Using the app endpoints as with the "classic" greeting app - -These normal greeting app endpoints work just as in the original greeting app: - -```shell -curl -X GET http://localhost:8080/greet -#Output: {"message":"Hello World!"} - -curl -X GET http://localhost:8080/greet/Joe -#Output: {"message":"Hello Joe!"} - -curl -X PUT -H "Content-Type: application/json" -d '{"message" : "Hola"}' http://localhost:8080/greet/greeting - -curl -X GET http://localhost:8080/greet/Jose -#Output: {"message":"Hola Jose!"} -``` - -## Using CORS - -### Sending "simple" CORS requests - -The following requests illustrate the CORS protocol with the example app. - -By setting `Origin` and `Host` headers that do not indicate the same system we trigger CORS processing in the - server: - -```shell -# Follow the CORS protocol for GET -curl -i -X GET -H "Origin: http://foo.com" -H "Host: here.com" http://localhost:8080/greet -``` -``` - -HTTP/1.1 200 OK -Access-Control-Allow-Origin: * -Content-Type: application/json -Date: Thu, 30 Apr 2020 17:25:51 -0500 -Vary: Origin -connection: keep-alive -content-length: 27 - -{"greeting":"Hola World!"} -``` -Note the new headers `Access-Control-Allow-Origin` and `Vary` in the response. - -The same happens for a `GET` requesting a personalized greeting (by passing the name of the - person to be greeted): -```shell -curl -i -X GET -H "Origin: http://foo.com" -H "Host: here.com" http://localhost:8080/greet/Joe -#Output: {"greeting":"Hola Joe!"} -``` -Take a look at `GreetResource` and in particular the methods named `optionsForXXX` near the end of the class. -There is one for each different subpath that the resource's endpoints handle: no subpath, `/{name}`, and `/greeting`. The -`@CrossOrigin` annotation on each defines the CORS behavior for the corresponding path. -The `optionsForUpdatingGreeting` gives specific origins and the HTTP method (`PUT`) constraints for sharing that -resource. The other two `optionsForRetrievingXXXGreeting` methods use default parameters for the `@CrossOrigin` -annotation: allowing all origins, all methods, etc. - -With this in mind, we can see why the two earlier `GET` `curl` requests work. - -These are what CORS calls "simple" requests; the CORS protocol for these adds headers to the request and response that -would be exchanged between the client and server even without CORS. - -### "Non-simple" CORS requests - -The CORS protocol requires the client to send a _pre-flight_ request before sending a request -that changes state on the server, such as `PUT` or `DELETE` and to check the returned status -and headers to make sure the server is willing to accept the actual request. CORS refers to such `PUT` and `DELETE` -requests as "non-simple" ones. - -This command sends a pre-flight `OPTIONS` request to see if the server will accept a subsequent `PUT` request from the -specified origin to change the greeting: -```shell -curl -i -X OPTIONS \ - -H "Access-Control-Request-Method: PUT" \ - -H "Origin: http://foo.com" \ - -H "Host: here.com" \ - http://localhost:8080/greet/greeting -``` -``` -HTTP/1.1 200 OK -Access-Control-Allow-Methods: PUT -Access-Control-Allow-Origin: http://foo.com -Date: Thu, 30 Apr 2020 17:30:59 -0500 -transfer-encoding: chunked -connection: keep-alive -``` -The successful status and the returned `Access-Control-Allow-xxx` headers indicate that the - server accepted the pre-flight request. That means it is OK for us to send `PUT` request to perform the actual change - of greeting. (See below for how the server rejects a pre-flight request.) -```shell -curl -i -X PUT \ - -H "Origin: http://foo.com" \ - -H "Host: here.com" \ - -H "Access-Control-Allow-Methods: PUT" \ - -H "Access-Control-Allow-Origin: http://foo.com" \ - -H "Content-Type: application/json" \ - -d "{ \"message\" : \"Cheers\" }" \ - http://localhost:8080/greet/greeting -``` -``` -HTTP/1.1 204 No Content -Access-Control-Allow-Origin: http://foo.com -Date: Thu, 30 Apr 2020 17:32:55 -0500 -Vary: Origin -connection: keep-alive -``` -And we run one more `GET` to observe the change in the greeting: -```shell -curl -i -X GET -H "Origin: http://foo.com" -H "Host: here.com" http://localhost:8080/greet/Joe -#Output: {"greeting":"Cheers Joe!"} -``` -Note that the tests in the example `TestCORS` class follow these same steps. - - diff --git a/examples/microprofile/cors/pom.xml b/examples/microprofile/cors/pom.xml deleted file mode 100644 index 86a58ad8791..00000000000 --- a/examples/microprofile/cors/pom.xml +++ /dev/null @@ -1,107 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.microprofile - helidon-examples-microprofile-cors - Helidon Examples Microprofile CORS - - - Microprofile example showing CORS support - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.microprofile - helidon-microprofile-cors - - - org.glassfish.jersey.media - jersey-media-json-binding - runtime - - - io.smallrye - jandex - runtime - true - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.webclient - helidon-webclient - test - - - io.helidon.http.media - helidon-http-media-jsonb - test - - - io.helidon.logging - helidon-logging-jul - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/microprofile/cors/src/main/java/io/helidon/microprofile/examples/cors/GreetResource.java b/examples/microprofile/cors/src/main/java/io/helidon/microprofile/examples/cors/GreetResource.java deleted file mode 100644 index 3975512f249..00000000000 --- a/examples/microprofile/cors/src/main/java/io/helidon/microprofile/examples/cors/GreetResource.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.microprofile.examples.cors; - -import io.helidon.microprofile.cors.CrossOrigin; - -import jakarta.enterprise.context.RequestScoped; -import jakarta.inject.Inject; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.HttpMethod; -import jakarta.ws.rs.OPTIONS; -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 with CORS support. - */ -@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 GreetingMessage} - */ - @GET - @Produces(MediaType.APPLICATION_JSON) - public GreetingMessage getDefaultMessage() { - return createResponse("World"); - } - - /** - * Return a greeting message using the name that was provided. - * - * @param name the name to greet - * @return {@link GreetingMessage} - */ - @Path("/{name}") - @GET - @Produces(MediaType.APPLICATION_JSON) - public GreetingMessage getMessage(@PathParam("name") String name) { - return createResponse(name); - } - - /** - * Set the greeting to use in future messages. - * - * @param message {@link GreetingMessage} containing the new greeting - * @return {@link Response} - */ - @Path("/greeting") - @PUT - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @RequestBody(name = "message", - required = true, - content = @Content(mediaType = "application/json", - schema = @Schema(type = SchemaType.OBJECT, requiredProperties = { "message" }))) - @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(GreetingMessage message) { - - if (message.getMessage() == null) { - GreetingMessage entity = new GreetingMessage("No greeting provided"); - return Response.status(Response.Status.BAD_REQUEST).entity(entity).build(); - } - - greetingProvider.setMessage(message.getMessage()); - return Response.status(Response.Status.NO_CONTENT).build(); - } - - /** - * CORS set-up for updateGreeting. - */ - @OPTIONS - @Path("/greeting") - @CrossOrigin(value = {"http://foo.com", "http://there.com"}, - allowMethods = {HttpMethod.PUT}) - @APIResponses({ - @APIResponse(name = "normal", responseCode = "200", description = "Preflight request granted"), - @APIResponse(name = "bad preflight", responseCode = "403", - description = "Preflight request denied")}) - public void optionsForUpdatingGreeting() { - } - - /** - * CORS set-up for getDefaultMessage. - */ - @OPTIONS - @CrossOrigin() - public void optionsForRetrievingUnnamedGreeting() { - } - - /** - * CORS set-up for getMessage. - */ - @OPTIONS - @CrossOrigin() - @Path("/{name}") - public void optionsForRetrievingNamedGreeting() { - } - - private GreetingMessage createResponse(String who) { - String msg = String.format("%s %s!", greetingProvider.getMessage(), who); - return new GreetingMessage(msg); - } -} diff --git a/examples/microprofile/cors/src/main/java/io/helidon/microprofile/examples/cors/GreetingMessage.java b/examples/microprofile/cors/src/main/java/io/helidon/microprofile/examples/cors/GreetingMessage.java deleted file mode 100644 index 82934aee6ae..00000000000 --- a/examples/microprofile/cors/src/main/java/io/helidon/microprofile/examples/cors/GreetingMessage.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2023 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.microprofile.examples.cors; - -/** - * POJO defining the greeting message content. - */ -@SuppressWarnings("unused") -public class GreetingMessage { - private String message; - - /** - * Create a new GreetingMessage instance. - */ - public GreetingMessage() { - } - - /** - * Create a new GreetingMessage instance. - * - * @param message message - */ - public GreetingMessage(String message) { - this.message = message; - } - - /** - * Gets the message value. - * - * @return message value - */ - public String getMessage() { - return message; - } - - /** - * Sets the message value. - * - * @param message message value to set - */ - public void setMessage(String message) { - this.message = message; - } -} diff --git a/examples/microprofile/cors/src/main/java/io/helidon/microprofile/examples/cors/GreetingProvider.java b/examples/microprofile/cors/src/main/java/io/helidon/microprofile/examples/cors/GreetingProvider.java deleted file mode 100644 index c790b3264d8..00000000000 --- a/examples/microprofile/cors/src/main/java/io/helidon/microprofile/examples/cors/GreetingProvider.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.microprofile.examples.cors; - -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/cors/src/main/java/io/helidon/microprofile/examples/cors/package-info.java b/examples/microprofile/cors/src/main/java/io/helidon/microprofile/examples/cors/package-info.java deleted file mode 100644 index 744088dc8a2..00000000000 --- a/examples/microprofile/cors/src/main/java/io/helidon/microprofile/examples/cors/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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. - */ - -/** - * Helidon MicroProfile CORS example. - */ -package io.helidon.microprofile.examples.cors; diff --git a/examples/microprofile/cors/src/main/resources/META-INF/beans.xml b/examples/microprofile/cors/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 4a5ec955fb7..00000000000 --- a/examples/microprofile/cors/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/microprofile/cors/src/main/resources/META-INF/microprofile-config.properties b/examples/microprofile/cors/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index a2dfe23f0a4..00000000000 --- a/examples/microprofile/cors/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) 2020 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. -# -app.greeting=Hello - -# Override configuration to use a random port for the unit tests -config_ordinal=1000 -# Microprofile server properties -server.port=8080 -server.host=0.0.0.0 diff --git a/examples/microprofile/cors/src/main/resources/logging.properties b/examples/microprofile/cors/src/main/resources/logging.properties deleted file mode 100644 index 1e689005fb3..00000000000 --- a/examples/microprofile/cors/src/main/resources/logging.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright (c) 2020, 2023 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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.cors.level=INFO diff --git a/examples/microprofile/cors/src/test/java/io/helidon/microprofile/examples/cors/TestCORS.java b/examples/microprofile/cors/src/test/java/io/helidon/microprofile/examples/cors/TestCORS.java deleted file mode 100644 index 2673f5b4539..00000000000 --- a/examples/microprofile/cors/src/test/java/io/helidon/microprofile/examples/cors/TestCORS.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.microprofile.examples.cors; - -import java.util.List; -import java.util.Optional; - -import io.helidon.common.media.type.MediaTypes; -import io.helidon.config.Config; -import io.helidon.http.HeaderNames; -import io.helidon.http.Headers; -import io.helidon.http.Method; -import io.helidon.http.media.jsonb.JsonbSupport; -import io.helidon.microprofile.server.Server; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientRequest; -import io.helidon.webclient.http1.Http1ClientResponse; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; - -import static io.helidon.cors.CrossOriginConfig.ACCESS_CONTROL_ALLOW_METHODS; -import static io.helidon.cors.CrossOriginConfig.ACCESS_CONTROL_ALLOW_ORIGIN; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.empty; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; - -@TestMethodOrder(MethodOrderer.OrderAnnotation.class) -public class TestCORS { - - private static Http1Client client; - private static Server server; - - @BeforeAll - static void init() { - Config config = Config.create(); - Config serverConfig = config.get("server"); - Server.Builder serverBuilder = Server.builder(); - serverConfig.ifExists(serverBuilder::config); - server = serverBuilder - .port(-1) // override the port for testing - .build() - .start(); - client = Http1Client.builder() - .baseUri("http://localhost:" + server.port()) - .addMediaSupport(JsonbSupport.create(config)) - .build(); - } - - @AfterAll - static void cleanup() { - if (server != null) { - server.stop(); - } - } - - @Order(1) // Make sure this runs before the greeting message changes so responses are deterministic. - @Test - public void testHelloWorld() { - - Http1ClientResponse r = getResponse("/greet"); - - assertThat("HTTP response1", r.status().code(), is(200)); - assertThat("default message", fromPayload(r), is("Hello World!")); - - r = getResponse("/greet/Joe"); - assertThat("HTTP response2", r.status().code(), is(200)); - assertThat("Hello Joe message", fromPayload(r), is("Hello Joe!")); - - r = putResponse("/greet/greeting", "Hola"); - assertThat("HTTP response3", r.status().code(), is(204)); - - r = getResponse("/greet/Jose"); - assertThat("HTTP response4", r.status().code(), is(200)); - assertThat("Hola Jose message", fromPayload(r), is("Hola Jose!")); - - r = getResponse("/health"); - assertThat("HTTP response health", r.status().code(), is(200)); - - r = getResponse("/metrics"); - assertThat("HTTP response metrics", r.status().code(), is(200)); - } - - @Order(10) // Run after the non-CORS tests (so the greeting is Hola) but before the CORS test that changes the greeting again. - @Test - void testAnonymousGreetWithCors() { - Http1ClientRequest req = client.get() - .header(HeaderNames.ORIGIN, "http://foo.com") - .header(HeaderNames.HOST, "here.com"); - - Http1ClientResponse r = getResponse("/greet", req); - assertThat("HTTP response", r.status().code(), is(200)); - String payload = fromPayload(r); - assertThat("HTTP response payload", payload, is("Hola World!")); - Headers responseHeaders = r.headers(); - Optional allowOrigin = responseHeaders.value(HeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN); - assertThat("Expected CORS header " + ACCESS_CONTROL_ALLOW_ORIGIN + " is present", - allowOrigin.isPresent(), is(true)); - assertThat("CORS header " + ACCESS_CONTROL_ALLOW_ORIGIN, allowOrigin.get(), is("*")); - } - - @Order(11) // Run after the non-CORS tests but before other CORS tests. - @Test - void testGreetingChangeWithCors() { - - // Send the pre-flight request and check the response. - - Http1ClientRequest req = client.method(Method.OPTIONS) - .header(HeaderNames.ORIGIN, "http://foo.com") - .header(HeaderNames.HOST, "here.com") - .header(HeaderNames.ACCESS_CONTROL_REQUEST_METHOD, "PUT"); - - List allowOrigins; - Headers responseHeaders; - Headers preflightResponseHeaders; - try (Http1ClientResponse res = req.path("/greet/greeting").request()) { - assertThat("pre-flight status", res.status().code(), is(200)); - preflightResponseHeaders = res.headers(); - } - - List allowMethods = preflightResponseHeaders.values(HeaderNames.ACCESS_CONTROL_ALLOW_METHODS); - assertThat("pre-flight response check for " + ACCESS_CONTROL_ALLOW_METHODS, allowMethods, is(not(empty()))); - assertThat("Header " + ACCESS_CONTROL_ALLOW_METHODS, allowMethods, contains("PUT")); - - allowOrigins = preflightResponseHeaders.values(HeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN); - - assertThat("pre-flight response check for " + ACCESS_CONTROL_ALLOW_ORIGIN, allowOrigins, is(not(empty()))); - assertThat("Header " + ACCESS_CONTROL_ALLOW_ORIGIN, allowOrigins, contains("http://foo.com")); - - // Send the follow-up request. - - req = client.put() - .header(HeaderNames.ORIGIN, "http://foo.com") - .header(HeaderNames.HOST, "here.com"); - preflightResponseHeaders.forEach(req.headers()::add); - - try (Http1ClientResponse res = putResponse("/greet/greeting", "Cheers", req)) { - assertThat("HTTP response3", res.status().code(), is(204)); - responseHeaders = res.headers(); - } - - allowOrigins = responseHeaders.values(HeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN); - assertThat("Expected CORS header " + ACCESS_CONTROL_ALLOW_ORIGIN, allowOrigins, is(not(empty()))); - assertThat("Header " + ACCESS_CONTROL_ALLOW_ORIGIN, allowOrigins, contains("http://foo.com")); - } - - @Order(12) // Run after CORS test changes greeting to Cheers. - @Test - void testNamedGreetWithCors() { - Http1ClientRequest req = client.get() - .header(HeaderNames.ORIGIN, "http://foo.com") - .header(HeaderNames.HOST, "here.com"); - - Http1ClientResponse r = getResponse("/greet/Maria", req); - assertThat("HTTP response", r.status().code(), is(200)); - assertThat(fromPayload(r), containsString("Cheers Maria")); - Headers responseHeaders = r.headers(); - Optional allowOrigin = responseHeaders.value(HeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN); - assertThat("Expected CORS header " + ACCESS_CONTROL_ALLOW_ORIGIN + " presence check", allowOrigin.isPresent(), is(true)); - assertThat(allowOrigin.get(), is("*")); - } - - @Order(100) // After all other tests, so we can rely on deterministic greetings. - @Test - void testGreetingChangeWithCorsAndOtherOrigin() { - Http1ClientRequest req = client.put() - .header(HeaderNames.ORIGIN, "http://other.com") - .header(HeaderNames.HOST, "here.com"); - - try (Http1ClientResponse r = putResponse("/greet/greeting", "Ahoy", req)) { - // Result depends on whether we are using overrides or not. - boolean isOverriding = Config.create().get("cors").exists(); - assertThat("HTTP response3", r.status().code(), is(isOverriding ? 204 : 403)); - } - } - - - private static Http1ClientResponse getResponse(String path) { - return getResponse(path, client.get()); - } - - private static Http1ClientResponse getResponse(String path, Http1ClientRequest builder) { - return builder.accept(MediaTypes.APPLICATION_JSON) - .path(path) - .request(); - } - - private static String fromPayload(Http1ClientResponse response) { - GreetingMessage message = response - .entity() - .as(GreetingMessage.class); - return message.getMessage(); - } - - private static GreetingMessage toPayload(String message) { - return new GreetingMessage(message); - } - - private static Http1ClientResponse putResponse(String path, String message) { - return putResponse(path, message, client.put()); - } - - private static Http1ClientResponse putResponse(String path, String message, Http1ClientRequest builder) { - return builder.accept(MediaTypes.APPLICATION_JSON) - .path(path) - .submit(toPayload(message)); - } -} diff --git a/examples/microprofile/cors/src/test/resources/logging.properties b/examples/microprofile/cors/src/test/resources/logging.properties deleted file mode 100644 index b3d32eef259..00000000000 --- a/examples/microprofile/cors/src/test/resources/logging.properties +++ /dev/null @@ -1,37 +0,0 @@ -# -# Copyright (c) 2020, 2024 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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.cors.level=FINE -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.microprofile.level=INFO -#io.helidon.common.level=INFO -#org.glassfish.jersey.level=INFO -#org.jboss.weld=INFO diff --git a/examples/microprofile/graphql/README.md b/examples/microprofile/graphql/README.md deleted file mode 100644 index aed1a6d8437..00000000000 --- a/examples/microprofile/graphql/README.md +++ /dev/null @@ -1,266 +0,0 @@ -# Microprofile GraphQL Example - -This example creates a simple Task API using Helidon's implementation of the Microprofile GraphQL API Specification. - -See [here](https://github.com/eclipse/microprofile-graphql) for more information on the -Microprofile GraphQL Specification as well as the [Helidon documentation](https://helidon.io/docs/v2/#/mp/introduction/01_introduction) -for an introduction to using GraphQL in Helidon MP. - -## Running the example - -1. Build - -```shell -mvn clean install -``` - -2. Run the example - -```shell -java -jar target/helidon-examples-microprofile-graphql.jar -``` - -## Issuing GraphQL requests via REST - -Access the `/graphql` endpoint via `http://127.0.0.1:7001/graphql`: - -1. Display the generated GraphQL Schema - - ```shell - curl http://127.0.0.1:7001/graphql/schema.graphql - ``` - - This will produce the following: - - ```graphql - type Mutation { - "Create a task with the given description" - createTask(description: String!): Task - "Remove all completed tasks and return the tasks left" - deleteCompletedTasks: [Task] - "Delete a task and return the deleted task details" - deleteTask(id: String!): Task - "Update a task" - updateTask(completed: Boolean, description: String, id: String!): Task - } - - type Query { - "Return a given task" - findTask(id: String!): Task - "Query tasks and optionally specified only completed" - tasks(completed: Boolean): [Task] - } - - type Task { - completed: Boolean! - createdAt: BigInteger! - description: String - id: String - } - - "Custom: Built-in java.math.BigInteger" - scalar BigInteger - ``` - -1. Create a Task - - ```shell - curl -X POST http://127.0.0.1:7001/graphql -d '{"query":"mutation createTask { createTask(description: \"Task Description 1\") { id description createdAt completed }}"}' - ``` - - Response is a newly created task: - - ```json - {"data":{"createTask":{"id":"0d4a8d","description":"Task Description 1","createdAt":1605501774877,"completed":false}} - ``` - -## Accessing Metrics - -In [TaskApi.java](src/main/java/io/helidon/examples/graphql/basics/TaskApi.java), the [Microprofile Metrics](https://github.com/eclipse/microprofile-metrics) -annotation`@SimplyTimed` has been added to the class which will apply simple timing metrics to all methods. After -exercising the APIs, access the metrics endpoint at http://127.0.0.1:7001/metrics to see all metrics. -In the case below we have also appended `/application` to the URL to just retrieve the application metrics. - -> Note: `jq` has been used to format the JSON output. This can be downloaded from https://stedolan.github.io/jq/download/ or you can -> format the output with an alternate utility. - -```shell -curl -H 'Accept: application/json' http://127.0.0.1:7001/metrics/application | jq -``` -``` -{ - "io.helidon.examples.graphql.basics.TaskApi.TaskApi": { - "count": 1, - "elapsedTime": 0.000440414 - }, - "io.helidon.examples.graphql.basics.TaskApi.createTask": { - "count": 1, - "elapsedTime": 0.000112074 - }, - "io.helidon.examples.graphql.basics.TaskApi.deleteCompletedTasks": { - "count": 0, - "elapsedTime": 0 - }, - "io.helidon.examples.graphql.basics.TaskApi.deleteTask": { - "count": 0, - "elapsedTime": 0 - }, - "io.helidon.examples.graphql.basics.TaskApi.findTask": { - "count": 0, - "elapsedTime": 0 - }, - "io.helidon.examples.graphql.basics.TaskApi.getTasks": { - "count": 0, - "elapsedTime": 0 - }, - "io.helidon.examples.graphql.basics.TaskApi.updateTask": { - "count": 0, - "elapsedTime": 0 - } -} -``` - -## Incorporating the GraphiQL UI - -The [GraphiQL UI](https://github.com/graphql/graphiql), which provides a UI to execute GraphQL commands, is not included by default in Helidon's Microprofile GraphQL -implementation. You can follow the guide below to incorporate the UI into this example: - -1. Add the following contents to the sample `examples/microprofile/graphql/src/main/resources/web/index.html` file, which has been included below from [here](https://github.com/graphql/graphiql/blob/main/packages/graphiql/README.md) -for convenience. - - ```html - - - Simple GraphiQL Example - - - -
      - - - - - - - - - ``` - - > Note: If you copy the original file, change the URL in the line `fetch('https://my/graphql', {` to `http://127.0.0.1:7001/graphql` - -1. Build and run the example using the instructions above. - -1. Access the GraphiQL UI via the following URL: http://127.0.0.1:7001/ui. - -2. Copy the following commands into the editor on the left. - - ```graphql - # Fragment to allow shorcut to display all fields for a task - fragment task on Task { - id - description - createdAt - completed - } - - # Create a task - mutation createTask { - createTask(description: "Task Description 1") { - ...task - } - } - - # Find all the tasks - query findAllTasks { - tasks { - ...task - } - } - - # Find a task - query findTask { - findTask(id: "251474") { - ...task - } - } - - # Find completed Tasks - query findCompletedTasks { - tasks(completed: true) { - ...task - } - } - - # Find outstanding Tasks - query findOutstandingTasks { - tasks(completed: false) { - ...task - } - } - - mutation updateTask { - updateTask(id: "251474" description:"New Description") { - ...task - } - } - - mutation completeTask { - updateTask(id: "251474" completed:true) { - ...task - } - } - - # Delete a task - mutation deleteTask { - deleteTask(id: "1f6ae5") { - ...task - } - } - - # Delete completed - mutation deleteCompleted { - deleteCompletedTasks { - ...task - } - } - ``` - -3. Run individual commands by clicking on the `Play` button and choosing the query or mutation to run. - -4. Sample requests - - 1. Execute `createTask` - 2. Change the description and execute `createTask` - 3. Execute `findTask` to show the exception when a task does not exist - 3. Change the id and execute `findTask` to show your newly created task - 5. Execute `findAllTasks` to show the 2 tasks - 6. Change the id and execute `updateTask` to update the existing task - 7. Change the id and execute `completeTask` - 8. Execute `findAllTasks` to show the task completed - 9. Execute `findCompletedTasks` to show only completed tasks - 10. Execute `deleteCompleted` to delete completed task - 11. Execute `findCompletedTasks` to show no completed tasks - - diff --git a/examples/microprofile/graphql/pom.xml b/examples/microprofile/graphql/pom.xml deleted file mode 100644 index 8477e99694a..00000000000 --- a/examples/microprofile/graphql/pom.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.microprofile - helidon-examples-microprofile-graphql - Helidon Examples Microprofile GraphQL - - - Usage of GraphQL in Helidon MP - - - - - io.helidon.microprofile.graphql - helidon-microprofile-graphql-server - - - io.helidon.microprofile.bundles - helidon-microprofile - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/microprofile/graphql/src/main/java/io/helidon/examples/graphql/basics/Task.java b/examples/microprofile/graphql/src/main/java/io/helidon/examples/graphql/basics/Task.java deleted file mode 100644 index 1ed8d580f1e..00000000000 --- a/examples/microprofile/graphql/src/main/java/io/helidon/examples/graphql/basics/Task.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2020 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.graphql.basics; - -import java.util.UUID; - -import io.helidon.common.Reflected; - -import org.eclipse.microprofile.graphql.NonNull; - -/** - * A data class representing a single To Do List task. - */ -@Reflected -public class Task { - - /** - * The creation time. - */ - private long createdAt; - - /** - * The completion status. - */ - private boolean completed; - - /** - * The task ID. - */ - @NonNull - private String id; - - /** - * The task description. - */ - @NonNull - private String description; - - /** - * Deserialization constructor. - */ - public Task() { - } - - /** - * Construct Task instance. - * - * @param description task description - */ - public Task(String description) { - this.id = UUID.randomUUID().toString().substring(0, 6); - this.createdAt = System.currentTimeMillis(); - this.description = description; - this.completed = false; - } - - /** - * Get the creation time. - * - * @return the creation time - */ - public long getCreatedAt() { - return createdAt; - } - - /** - * Get the task ID. - * - * @return the task ID - */ - public String getId() { - return id; - } - - /** - * Get the task description. - * - * @return the task description - */ - public String getDescription() { - return description; - } - - /** - * Set the task description. - * - * @param description the task description - */ - public void setDescription(String description) { - this.description = description; - } - - /** - * Get the completion status. - * - * @return true if it is completed, false otherwise. - */ - public boolean isCompleted() { - return completed; - } - - /** - * Sets the completion status. - * - * @param completed the completion status - */ - public void setCompleted(boolean completed) { - this.completed = completed; - } - - @Override - public String toString() { - return "Task{" - + "id=" + id - + ", description=" + description - + ", completed=" + completed - + '}'; - } -} diff --git a/examples/microprofile/graphql/src/main/java/io/helidon/examples/graphql/basics/TaskApi.java b/examples/microprofile/graphql/src/main/java/io/helidon/examples/graphql/basics/TaskApi.java deleted file mode 100644 index fa15b956bd3..00000000000 --- a/examples/microprofile/graphql/src/main/java/io/helidon/examples/graphql/basics/TaskApi.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.graphql.basics; - -import java.util.Collection; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; - -import jakarta.enterprise.context.ApplicationScoped; -import org.eclipse.microprofile.graphql.Description; -import org.eclipse.microprofile.graphql.GraphQLApi; -import org.eclipse.microprofile.graphql.Mutation; -import org.eclipse.microprofile.graphql.Name; -import org.eclipse.microprofile.graphql.NonNull; -import org.eclipse.microprofile.graphql.Query; -import org.eclipse.microprofile.metrics.annotation.Timed; - -/** - * A CDI Bean that exposes a GraphQL API to query and mutate {@link Task}s. - */ -@GraphQLApi -@ApplicationScoped -@Timed -public class TaskApi { - - private static final String MESSAGE = "Unable to find task with id "; - - private Map tasks = new ConcurrentHashMap<>(); - - /** - * Create a {@link Task}. - * - * @param description task description - * @return the created {@link Task} - */ - @Mutation - @Description("Create a task with the given description") - public Task createTask(@Name("description") @NonNull String description) { - if (description == null) { - throw new IllegalArgumentException("Description must be provided"); - } - Task task = new Task(description); - tasks.put(task.getId(), task); - return task; - } - - /** - * Query {@link Task}s. - * - * @param completed optionally specify completion status - * @return a {@link Collection} of {@link Task}s - */ - @Query - @Description("Query tasks and optionally specify only completed") - public Collection getTasks(@Name("completed") Boolean completed) { - return tasks.values().stream() - .filter(task -> completed == null || task.isCompleted() == completed) - .collect(Collectors.toList()); - } - - /** - * Return a {@link Task}. - * - * @param id task id - * @return the {@link Task} with the given id - * @throws TaskNotFoundException if the task was not found - */ - @Query - @Description("Return a given task") - public Task findTask(@Name("id") @NonNull String id) throws TaskNotFoundException { - return Optional.ofNullable(tasks.get(id)) - .orElseThrow(() -> new TaskNotFoundException(MESSAGE + id)); - } - - /** - * Delete a {@link Task}. - * - * @param id task to delete - * @return the deleted {@link Task} - * @throws TaskNotFoundException if the task was not found - */ - @Mutation - @Description("Delete a task and return the deleted task details") - public Task deleteTask(@Name("id") @NonNull String id) throws TaskNotFoundException { - return Optional.ofNullable(tasks.remove(id)) - .orElseThrow(() -> new TaskNotFoundException(MESSAGE + id)); - } - - /** - * Remove all completed {@link Task}s. - * - * @return the {@link Task}s left - */ - @Mutation - @Description("Remove all completed tasks and return the tasks left") - public Collection deleteCompletedTasks() { - tasks.values().removeIf(Task::isCompleted); - return tasks.values(); - } - - /** - * Update a {@link Task}. - * - * @param id task to update - * @param description optional description - * @param completed optional completed - * @return the updated {@link Task} - * @throws TaskNotFoundException if the task was not found - */ - @Mutation - @Description("Update a task") - public Task updateTask(@Name("id") @NonNull String id, - @Name("description") String description, - @Name("completed") Boolean completed) throws TaskNotFoundException { - - try { - return tasks.compute(id, (k, v) -> { - Objects.requireNonNull(v); - - if (description != null) { - v.setDescription(description); - } - if (completed != null) { - v.setCompleted(completed); - } - return v; - }); - } catch (Exception e) { - throw new TaskNotFoundException(MESSAGE + id); - } - } -} diff --git a/examples/microprofile/graphql/src/main/java/io/helidon/examples/graphql/basics/TaskNotFoundException.java b/examples/microprofile/graphql/src/main/java/io/helidon/examples/graphql/basics/TaskNotFoundException.java deleted file mode 100644 index 12a4cbe5a63..00000000000 --- a/examples/microprofile/graphql/src/main/java/io/helidon/examples/graphql/basics/TaskNotFoundException.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2020 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.graphql.basics; - -/** - * An exception indicating that a {@link Task} was not found. - */ -public class TaskNotFoundException extends Exception { - /** - * Create the exception. - * @param message reason for the exception. - */ - public TaskNotFoundException(String message) { - super(message); - } -} diff --git a/examples/microprofile/graphql/src/main/java/io/helidon/examples/graphql/basics/package-info.java b/examples/microprofile/graphql/src/main/java/io/helidon/examples/graphql/basics/package-info.java deleted file mode 100644 index f9b68f8a523..00000000000 --- a/examples/microprofile/graphql/src/main/java/io/helidon/examples/graphql/basics/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020, 2021 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. - */ - -/** - * A set of small usage examples. Start with {@link io.helidon.grpc.examples.basics.Main} class. - */ -package io.helidon.examples.graphql.basics; diff --git a/examples/microprofile/graphql/src/main/resources/META-INF/beans.xml b/examples/microprofile/graphql/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 4a5ec955fb7..00000000000 --- a/examples/microprofile/graphql/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/microprofile/graphql/src/main/resources/META-INF/microprofile-config.properties b/examples/microprofile/graphql/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 6c47520db6c..00000000000 --- a/examples/microprofile/graphql/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2020 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.static.classpath.context=/ui -server.static.classpath.location=/web -graphql.cors=Access-Control-Allow-Origin -mp.graphql.exceptionsWhiteList=java.lang.IllegalArgumentException diff --git a/examples/microprofile/graphql/src/main/resources/logging.properties b/examples/microprofile/graphql/src/main/resources/logging.properties deleted file mode 100644 index c2b6684a4a1..00000000000 --- a/examples/microprofile/graphql/src/main/resources/logging.properties +++ /dev/null @@ -1,24 +0,0 @@ -# -# Copyright (c) 2020, 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. -# - -handlers=io.helidon.logging.jul.HelidonConsoleHandler - -io.helidon.logging.jul.HelidonConsoleHandler.level=ALL -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 - -#All log level details -.level=WARNING -io.helidon.level=INFO diff --git a/examples/microprofile/graphql/src/main/resources/web/index.html b/examples/microprofile/graphql/src/main/resources/web/index.html deleted file mode 100644 index 56c4b2ce1a3..00000000000 --- a/examples/microprofile/graphql/src/main/resources/web/index.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - Sample - -

      To enable GraphiQL UI please see the Microprofile GraphQL example README.md

      -

      - \ No newline at end of file diff --git a/examples/microprofile/hello-world-explicit/README.md b/examples/microprofile/hello-world-explicit/README.md deleted file mode 100644 index e93f7a68911..00000000000 --- a/examples/microprofile/hello-world-explicit/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Helidon MP Hello World Explicit Example - -This examples shows a simple application written using Helidon MP. -It is explicit because in this example you write the `main` class -and explicitly start the microprofile server. - -```shell -mvn package -java -jar target/helidon-examples-microprofile-hello-world-explicit.jar -``` - -Then try the endpoints: - -```shell -curl -X GET http://localhost:7001/helloworld -curl -X GET http://localhost:7001/helloworld/earth -``` - -By default the server will use a dynamic port, see the messages displayed -when the application starts. diff --git a/examples/microprofile/hello-world-explicit/pom.xml b/examples/microprofile/hello-world-explicit/pom.xml deleted file mode 100644 index 5fc855dd99c..00000000000 --- a/examples/microprofile/hello-world-explicit/pom.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../applications/mp/pom.xml - - helidon-examples-microprofile-hello-world-explicit - Helidon Examples Microprofile Explicit Hello World - - - Microprofile example with explicit bootstrapping (Server.create(Application.class).start()) - - - - io.helidon.microprofile.example.helloworld.explicit.Main - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.smallrye - jandex - runtime - true - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/microprofile/hello-world-explicit/src/main/java/io/helidon/microprofile/example/helloworld/explicit/HelloWorldResource.java b/examples/microprofile/hello-world-explicit/src/main/java/io/helidon/microprofile/example/helloworld/explicit/HelloWorldResource.java deleted file mode 100644 index ec6b03bfe95..00000000000 --- a/examples/microprofile/hello-world-explicit/src/main/java/io/helidon/microprofile/example/helloworld/explicit/HelloWorldResource.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2018, 2021 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.microprofile.example.helloworld.explicit; - -import java.net.URI; -import java.util.Collections; - -import io.helidon.config.Config; - -import jakarta.enterprise.context.RequestScoped; -import jakarta.enterprise.inject.spi.BeanManager; -import jakarta.inject.Inject; -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -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; - -/** - * Example resource. - */ -@Path("helloworld") -@RequestScoped -public class HelloWorldResource { - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - private final Config config; - private final String applicationName; - private final URI applicationUri; - private BeanManager beanManager; - - /** - * Constructor injection of field values. - * - * @param config configuration instance - * @param appName name of application from config (app.name) - * @param appUri URI of application from config (app.uri) - * @param beanManager bean manager (injected automatically by CDI) - */ - @Inject - public HelloWorldResource(Config config, - @ConfigProperty(name = "app.name") String appName, - @ConfigProperty(name = "app.uri") URI appUri, - BeanManager beanManager) { - this.config = config; - this.applicationName = appName; - this.applicationUri = appUri; - this.beanManager = beanManager; - } - - /** - * Hello world GET method. - * - * @return string with application name - */ - @GET - @Produces(MediaType.TEXT_PLAIN) - public String message() { - return "Hello World from application " + applicationName; - } - - /** - * Hello World GET method returning JSON. - * - * @param name name to add to response - * @return JSON with name and configured fields of this class - */ - @Path("/{name}") - @GET - @Produces(MediaType.APPLICATION_JSON) - public JsonObject getHello(@PathParam("name") String name) { - return JSON.createObjectBuilder() - .add("name", name) - .add("appName", applicationName) - .add("appUri", String.valueOf(applicationUri)) - .add("config", config.get("my.property").asString().get()) - .add("beanManager", beanManager.toString()) - .build(); - } -} diff --git a/examples/microprofile/hello-world-explicit/src/main/java/io/helidon/microprofile/example/helloworld/explicit/Main.java b/examples/microprofile/hello-world-explicit/src/main/java/io/helidon/microprofile/example/helloworld/explicit/Main.java deleted file mode 100644 index c85566f5eac..00000000000 --- a/examples/microprofile/hello-world-explicit/src/main/java/io/helidon/microprofile/example/helloworld/explicit/Main.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2018, 2024 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.microprofile.example.helloworld.explicit; - -import io.helidon.microprofile.server.Server; - -/** - * Explicit example. - */ -public class Main { - private Main() { - } - - /** - * Starts server manually. - * - * @param args command line arguments (ignored) - */ - public static void main(String[] args) { - Server server = Server.builder() - .host("localhost") - // use port 7001 as per README.md - .port(7001) - .build(); - - server.start(); - - String endpoint = "http://" + server.host() + ":" + server.port(); - System.out.println("Started application on " + endpoint + "/helloworld"); - System.out.println("Metrics available on " + endpoint + "/metrics"); - System.out.println("Heatlh checks available on " + endpoint + "/health"); - - } -} diff --git a/examples/microprofile/hello-world-explicit/src/main/java/io/helidon/microprofile/example/helloworld/explicit/package-info.java b/examples/microprofile/hello-world-explicit/src/main/java/io/helidon/microprofile/example/helloworld/explicit/package-info.java deleted file mode 100644 index d170a0bfe83..00000000000 --- a/examples/microprofile/hello-world-explicit/src/main/java/io/helidon/microprofile/example/helloworld/explicit/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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. - */ - -/** - * Explicit example (configures server and resources). - */ -package io.helidon.microprofile.example.helloworld.explicit; diff --git a/examples/microprofile/hello-world-explicit/src/main/resources/META-INF/beans.xml b/examples/microprofile/hello-world-explicit/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 1b3fbc297cb..00000000000 --- a/examples/microprofile/hello-world-explicit/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/microprofile/hello-world-explicit/src/main/resources/META-INF/microprofile-config.properties b/examples/microprofile/hello-world-explicit/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 0a58d35be73..00000000000 --- a/examples/microprofile/hello-world-explicit/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2020 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. -# - -app.name=Hello World Application -app.uri=https://www.example.com - -my.property=propertyValue - -# Enable the optional MicroProfile Metrics REST.request metrics -metrics.rest-request.enabled=true diff --git a/examples/microprofile/hello-world-explicit/src/main/resources/logging.properties b/examples/microprofile/hello-world-explicit/src/main/resources/logging.properties deleted file mode 100644 index 54e59fec680..00000000000 --- a/examples/microprofile/hello-world-explicit/src/main/resources/logging.properties +++ /dev/null @@ -1,24 +0,0 @@ -# -# Copyright (c) 2018, 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. -# - -handlers=io.helidon.logging.jul.HelidonConsoleHandler - -io.helidon.logging.jul.HelidonConsoleHandler.level=ALL -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 - -#All log level details -.level=WARNING -io.helidon.level=INFO diff --git a/examples/microprofile/hello-world-implicit/README.md b/examples/microprofile/hello-world-implicit/README.md deleted file mode 100644 index e8d812a973f..00000000000 --- a/examples/microprofile/hello-world-implicit/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Helidon MP Hello World Implicit Example - -This examples shows a simple application written using Helidon MP. -It is implicit because in this example you don't write the -`main` class, instead you rely on the Microprofile Server main class. - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-microprofile-hello-world-implicit.jar -``` - -Then try the endpoints: - -```shell -curl -X GET http://localhost:7001/helloworld -curl -X GET http://localhost:7001/helloworld/earth -curl -X GET http://localhost:7001/another -``` diff --git a/examples/microprofile/hello-world-implicit/pom.xml b/examples/microprofile/hello-world-implicit/pom.xml deleted file mode 100644 index 73d7ee4b01a..00000000000 --- a/examples/microprofile/hello-world-implicit/pom.xml +++ /dev/null @@ -1,93 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.microprofile - helidon-examples-microprofile-hello-world-implicit - Helidon Examples Microprofile Implicit Hello World - - - Microprofile example with implicit bootstrapping (cdi.Main(new String[0]) - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.smallrye - jandex - runtime - true - - - io.helidon.logging - helidon-logging-jul - runtime - - - io.helidon.microprofile.testing - helidon-microprofile-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/AnotherResource.java b/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/AnotherResource.java deleted file mode 100644 index 11a8b6d6281..00000000000 --- a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/AnotherResource.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.microprofile.example.helloworld.implicit; - -import java.net.URI; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import jakarta.enterprise.context.RequestScoped; -import jakarta.inject.Inject; -import jakarta.inject.Provider; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import org.eclipse.microprofile.config.Config; -import org.eclipse.microprofile.config.inject.ConfigProperty; - -/** - * Resource showing all possible configuration injections. - */ -@Path("another") -@RequestScoped -public class AnotherResource { - @Inject - @ConfigProperty(name = "app.nonExistent", defaultValue = "145") - private int defaultValue; - - @Inject - @ConfigProperty(name = "app.nonExistent") - private Optional empty; - - @Inject - @ConfigProperty(name = "app.uri") - private Optional full; - - @Inject - @ConfigProperty(name = "app.someInt") - private Provider provider; - - @Inject - @ConfigProperty(name = "app.ints") - private List ints; - - @Inject - @ConfigProperty(name = "app.ints") - private Optional> optionalInts; - - @Inject - @ConfigProperty(name = "app.ints") - private Provider> providedInts; - - @Inject - @ConfigProperty(name = "app.ints") - private int[] intsArray; - - @Inject - @ConfigProperty(name = "app") - private Map detached; - - @Inject - private Config mpConfig; - - @Inject - private io.helidon.config.Config helidonConfig; - - /** - * Get method to validate that all injections worked. - * - * @return data from all fields of this class - */ - @GET - public String get() { - return toString(); - } - - @Override - public String toString() { - return "AnotherResource{" - + "defaultValue=" + defaultValue - + ", empty=" + empty - + ", full=" + full - + ", provider=" + provider + "(" + provider.get() + ")" - + ", ints=" + ints - + ", optionalInts=" + optionalInts - + ", providedInts=" + providedInts + "(" + providedInts.get() + ")" - + ", detached=" + detached - + ", microprofileConfig=" + mpConfig - + ", helidonConfig=" + helidonConfig - + ", intsArray=" + Arrays.toString(intsArray) - + '}'; - } -} diff --git a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/HelloWorldResource.java b/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/HelloWorldResource.java deleted file mode 100644 index 4fe49e4ca08..00000000000 --- a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/HelloWorldResource.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2018, 2021 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.microprofile.example.helloworld.implicit; - -import java.net.URI; -import java.util.Collections; -import java.util.logging.Logger; - -import io.helidon.config.Config; -import io.helidon.microprofile.example.helloworld.implicit.cdi.LoggerQualifier; -import io.helidon.microprofile.example.helloworld.implicit.cdi.RequestId; -import io.helidon.microprofile.example.helloworld.implicit.cdi.ResourceProducer; - -import jakarta.enterprise.context.RequestScoped; -import jakarta.enterprise.inject.spi.BeanManager; -import jakarta.inject.Inject; -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -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; - -/** - * Resource for hello world example. - */ -@Path("helloworld") -@RequestScoped -public class HelloWorldResource { - - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - private final Config config; - private final Logger logger; - private final int requestId; - private final String applicationName; - private final URI applicationUri; - private BeanManager beanManager; - - /** - * Using constructor injection for field values. - * - * @param config configuration instance - * @param logger logger (from {@link ResourceProducer} - * @param requestId requestId (from {@link ResourceProducer} - * @param appName name from configuration (app.name) - * @param appUri URI from configuration (app.uri) - * @param beanManager bean manager (injected automatically by CDI) - */ - @Inject - public HelloWorldResource(Config config, - @LoggerQualifier Logger logger, - @RequestId int requestId, - @ConfigProperty(name = "app.name") String appName, - @ConfigProperty(name = "app.uri") URI appUri, - BeanManager beanManager) { - this.config = config; - this.logger = logger; - this.requestId = requestId; - this.applicationName = appName; - this.applicationUri = appUri; - this.beanManager = beanManager; - } - - /** - * Get method for this resource, shows logger and request id. - * - * @return hello world - */ - @GET - @Produces(MediaType.TEXT_PLAIN) - public String message() { - return "Hello World: " + logger + ", request: " + requestId + ", appName: " + applicationName; - } - - /** - * Get method for this resource, returning JSON. - * - * @param name name to add to response - * @return JSON structure with injected fields - */ - @Path("/{name}") - @GET - @Produces(MediaType.APPLICATION_JSON) - public JsonObject getHello(@PathParam("name") String name) { - return JSON.createObjectBuilder() - .add("name", name) - .add("requestId", requestId) - .add("appName", applicationName) - .add("appUri", String.valueOf(applicationUri)) - .add("config", config.get("server.port").asInt().get()) - .add("beanManager", beanManager.toString()) - .add("logger", logger.getName()) - .build(); - } -} diff --git a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/LoggerQualifier.java b/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/LoggerQualifier.java deleted file mode 100644 index 7de3e86dbb7..00000000000 --- a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/LoggerQualifier.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2018, 2021 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.microprofile.example.helloworld.implicit.cdi; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import jakarta.inject.Qualifier; - -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * Use this qualifier to inject logger instances. - */ -@Qualifier -@Retention(RUNTIME) -@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE}) -public @interface LoggerQualifier { -} diff --git a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/RequestId.java b/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/RequestId.java deleted file mode 100644 index c4e904e6c5e..00000000000 --- a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/RequestId.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2018, 2021 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.microprofile.example.helloworld.implicit.cdi; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import jakarta.inject.Qualifier; - -/** - * Request id qualifier to inject increasing request id. - */ -@Qualifier -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE}) -public @interface RequestId { -} diff --git a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/RequestIdProducer.java b/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/RequestIdProducer.java deleted file mode 100644 index 2eacb8ff66d..00000000000 --- a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/RequestIdProducer.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2018, 2021 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.microprofile.example.helloworld.implicit.cdi; - -import jakarta.enterprise.context.ApplicationScoped; - -/** - * Produce an ever increasing request id. - */ -@ApplicationScoped -public class RequestIdProducer { - -} diff --git a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/ResourceProducer.java b/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/ResourceProducer.java deleted file mode 100644 index 206be30fb38..00000000000 --- a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/ResourceProducer.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2018, 2021 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.microprofile.example.helloworld.implicit.cdi; - -import java.util.concurrent.atomic.AtomicInteger; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.Produces; -import jakarta.enterprise.inject.spi.InjectionPoint; - -/** - * Producer for various resources required by this example. - */ -@ApplicationScoped -public class ResourceProducer { - private static final AtomicInteger COUNTER = new AtomicInteger(); - - /** - * Each injection will increase the COUNTER. - * - * @return increased COUNTER value - */ - @Produces - @RequestId - public int produceRequestId() { - return COUNTER.incrementAndGet(); - } - - /** - * Create/get a logger instance for the class that the logger is being injected into. - * - * @param injectionPoint injection point - * @return a logger instance - */ - @Produces - @LoggerQualifier - public java.util.logging.Logger produceLogger(final InjectionPoint injectionPoint) { - return java.util.logging.Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName()); - } -} diff --git a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/package-info.java b/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/package-info.java deleted file mode 100644 index 3de41659971..00000000000 --- a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/cdi/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2018, 2021 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. - */ - -/** - * CDI classes for example. - */ -package io.helidon.microprofile.example.helloworld.implicit.cdi; diff --git a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/package-info.java b/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/package-info.java deleted file mode 100644 index 19d08407637..00000000000 --- a/examples/microprofile/hello-world-implicit/src/main/java/io/helidon/microprofile/example/helloworld/implicit/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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. - */ - -/** - * Implicit HelloWorld example (starts server without configuration). - */ -package io.helidon.microprofile.example.helloworld.implicit; diff --git a/examples/microprofile/hello-world-implicit/src/main/resources/META-INF/beans.xml b/examples/microprofile/hello-world-implicit/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 1b3fbc297cb..00000000000 --- a/examples/microprofile/hello-world-implicit/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/microprofile/hello-world-implicit/src/main/resources/META-INF/microprofile-config.properties b/examples/microprofile/hello-world-implicit/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index bbae60a1ba5..00000000000 --- a/examples/microprofile/hello-world-implicit/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2020 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. -# - -app.name=Hello World Application -app.someInt=147 -app.uri=https://www.example.com -app.someInt=147 -app.ints=12,12,32,12,44 - -server.port=7001 - -# Enable the optional MicroProfile Metrics REST.request metrics -metrics.rest-request.enabled=true diff --git a/examples/microprofile/hello-world-implicit/src/main/resources/logging.properties b/examples/microprofile/hello-world-implicit/src/main/resources/logging.properties deleted file mode 100644 index c1abdd4a00f..00000000000 --- a/examples/microprofile/hello-world-implicit/src/main/resources/logging.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2018, 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. -# - -handlers=io.helidon.logging.jul.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=[%1$tc] %4$s: %2$s - %5$s %6$s%n -.level=INFO -io.helidon.microprofile.config.level=FINEST diff --git a/examples/microprofile/hello-world-implicit/src/test/java/io/helidon/microprofile/example/helloworld/implicit/ImplicitHelloWorldTest.java b/examples/microprofile/hello-world-implicit/src/test/java/io/helidon/microprofile/example/helloworld/implicit/ImplicitHelloWorldTest.java deleted file mode 100644 index f6d028341c8..00000000000 --- a/examples/microprofile/hello-world-implicit/src/test/java/io/helidon/microprofile/example/helloworld/implicit/ImplicitHelloWorldTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.microprofile.example.helloworld.implicit; - -import io.helidon.microprofile.testing.junit5.HelidonTest; - -import jakarta.inject.Inject; -import jakarta.json.JsonObject; -import jakarta.ws.rs.client.WebTarget; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.assertAll; - -/** - * Unit test for {@link HelloWorldResource}. - */ -@HelidonTest -class ImplicitHelloWorldTest { - private final WebTarget target; - - @Inject - ImplicitHelloWorldTest(WebTarget target) { - this.target = target; - } - @Test - void testJsonResource() { - JsonObject jsonObject = target - .path("/helloworld/unit") - .request() - .get(JsonObject.class); - - assertAll("JSON fields must match expected injection values", - () -> assertThat("Name from request", jsonObject.getString("name"), is("unit")), - () -> assertThat("Request id from CDI provider", jsonObject.getInt("requestId"), is(1)), - () -> assertThat("App name from config", jsonObject.getString("appName"), is("Hello World Application")), - () -> assertThat("Logger name", jsonObject.getString("logger"), is(HelloWorldResource.class.getName())) - ); - - } -} diff --git a/examples/microprofile/http-status-count-mp/README.md b/examples/microprofile/http-status-count-mp/README.md deleted file mode 100644 index e3329320be4..00000000000 --- a/examples/microprofile/http-status-count-mp/README.md +++ /dev/null @@ -1,76 +0,0 @@ -# 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 - -```shell -mvn package -java -jar target/http-status-count-mp.jar -``` - -## Exercise the application -```shell -curl -X GET http://localhost:8080/simple-greet -``` -```listing -{"message":"Hello World!"} -``` - -```shell -curl -X GET http://localhost:8080/greet -``` -```listing -{"message":"Hello World!"} -``` -```shell -curl -X GET http://localhost:8080/greet/Joe -``` -```listing -{"message":"Hello Joe!"} -``` -```shell -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 -```shell -# 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 - -```shell -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 deleted file mode 100644 index c893d52ddac..00000000000 --- a/examples/microprofile/http-status-count-mp/app.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# -# Copyright (c) 2018, 2023 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. -# - -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 deleted file mode 100644 index 85808447d49..00000000000 --- a/examples/microprofile/http-status-count-mp/pom.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples - http-status-count-mp - 1.0-SNAPSHOT - - Helidon Examples Metrics HTTP Status Counters - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - com.fasterxml.jackson.core - jackson-databind - - - org.eclipse.microprofile.metrics - microprofile-metrics-api - - - io.helidon.microprofile.metrics - helidon-microprofile-metrics - - - io.helidon.microprofile.health - helidon-microprofile-health - - - io.helidon.webserver.observe - helidon-webserver-observe-metrics - runtime - - - io.helidon.metrics - helidon-metrics-system-meters - runtime - - - io.helidon.logging - helidon-logging-jul - runtime - - - io.smallrye - jandex - runtime - - - io.helidon.microprofile.bundles - helidon-microprofile-core - - - org.junit.jupiter - junit-jupiter-api - test - - - io.helidon.microprofile.testing - helidon-microprofile-testing-junit5 - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - 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 deleted file mode 100644 index 5bcda14742f..00000000000 --- a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetResource.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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; -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 GreetingMessage} - */ - @GET - @Produces(MediaType.APPLICATION_JSON) - public GreetingMessage getDefaultMessage() { - return createResponse("World"); - } - - /** - * Return a greeting message using the name that was provided. - * - * @param name the name to greet - * @return {@link GreetingMessage} - */ - @Path("/{name}") - @GET - @Produces(MediaType.APPLICATION_JSON) - public GreetingMessage getMessage(@PathParam("name") String name) { - return createResponse(name); - } - - /** - * Set the greeting to use in future messages. - * - * @param message 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(GreetingMessage message) { - - if (message.getMessage() == null) { - GreetingMessage error = new GreetingMessage("No greeting provided"); - return Response.status(Response.Status.BAD_REQUEST).entity(error).build(); - } - - greetingProvider.setMessage(message.getMessage()); - return Response.status(Response.Status.NO_CONTENT).build(); - } - - private GreetingMessage createResponse(String who) { - String msg = String.format("%s %s!", greetingProvider.getMessage(), who); - - return new GreetingMessage(msg); - } -} diff --git a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetingMessage.java b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetingMessage.java deleted file mode 100644 index d30fc5dc71d..00000000000 --- a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetingMessage.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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; - -/** - * Greeting message. - */ -public class GreetingMessage { - private String message; - - /** - * Create a new GreetingMessage instance. - */ - public GreetingMessage() { - } - - /** - * Create a new GreetingMessage instance. - * - * @param message message - */ - public GreetingMessage(String message) { - this.message = message; - } - - /** - * Gets the message value. - * - * @return message value - */ - public String getMessage() { - return message; - } - - /** - * Sets the message value. - * - * @param message message value to set - */ - public void setMessage(String message) { - this.message = message; - } -} 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 deleted file mode 100644 index 95377db2797..00000000000 --- a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/GreetingProvider.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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; - -/** - * 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 deleted file mode 100644 index 8ea016163c6..00000000000 --- a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/HttpStatusMetricFilter.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.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) - .withDescription("Counts the number of HTTP responses in each status category (1xx, 2xx, etc.)") - .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/SimpleGreetResource.java b/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/SimpleGreetResource.java deleted file mode 100644 index 7516812b1ed..00000000000 --- a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/SimpleGreetResource.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.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; - -/** - * 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; - - /** - * 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; - } - - /** - * Return a worldly greeting message. - * - * @return {@link GreetingMessage} - */ - @GET - @Produces(MediaType.APPLICATION_JSON) - public GreetingMessage getDefaultMessage() { - String msg = String.format("%s %s!", message, "World"); - GreetingMessage message = new GreetingMessage(); - message.setMessage(msg); - 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) - @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 deleted file mode 100644 index 11bfe9067aa..00000000000 --- a/examples/microprofile/http-status-count-mp/src/main/java/io/helidon/examples/mp/httpstatuscount/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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/META-INF/beans.xml b/examples/microprofile/http-status-count-mp/src/main/resources/META-INF/beans.xml deleted file mode 100644 index f9537bf2569..00000000000 --- a/examples/microprofile/http-status-count-mp/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - 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 deleted file mode 100644 index affefe0a610..00000000000 --- a/examples/microprofile/http-status-count-mp/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright (c) 2022, 2023 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. -# - -# 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 deleted file mode 100644 index fe51488c706..00000000000 --- a/examples/microprofile/http-status-count-mp/src/main/resources/META-INF/native-image/reflect-config.json +++ /dev/null @@ -1 +0,0 @@ -[] 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 deleted file mode 100644 index 3a5ab924b72..00000000000 --- a/examples/microprofile/http-status-count-mp/src/main/resources/application.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# -# 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 deleted file mode 100644 index 769cf97330f..00000000000 --- a/examples/microprofile/http-status-count-mp/src/main/resources/logging.properties +++ /dev/null @@ -1,36 +0,0 @@ -# -# Copyright (c) 2022, 2024 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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 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 deleted file mode 100644 index c50d7d1c925..00000000000 --- a/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/MainTest.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.microprofile.testing.junit5.HelidonTest; - -import jakarta.inject.Inject; -import jakarta.ws.rs.client.Entity; -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.MetricRegistry; -import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; - -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(); - assertThat("Difference in personalized greeting counter between successive calls", after - before, is(1d)); - } - - @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 { - GreetingMessage message = target - .path("simple-greet") - .request() - .get(GreetingMessage.class); - assertThat(message.getMessage(), is("Hello World!")); - } - - @Test - public void testGreetings() throws Exception { - GreetingMessage jsonMessage = target - .path("greet/Joe") - .request() - .get(GreetingMessage.class); - assertThat(jsonMessage.getMessage(), is("Hello Joe!")); - - try (Response r = target - .path("greet/greeting") - .request() - .put(Entity.entity("{\"message\" : \"Hola\"}", MediaType.APPLICATION_JSON))) { - assertThat(r.getStatus(), is(204)); - } - - jsonMessage = target - .path("greet/Jose") - .request() - .get(GreetingMessage.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 deleted file mode 100644 index 38ca0eb5370..00000000000 --- a/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/StatusResource.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.http.Status; - -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 = Status.INTERNAL_SERVER_ERROR_500.code(); - msg = "Unsuccessful conversion"; - } - return status == 204 ? Response.status(204).build() : 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 deleted file mode 100644 index 220d87d3906..00000000000 --- a/examples/microprofile/http-status-count-mp/src/test/java/io/helidon/examples/mp/httpstatuscount/StatusTest.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.http.Status; -import io.helidon.microprofile.testing.junit5.AddBean; -import io.helidon.microprofile.testing.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 final Counter[] STATUS_COUNTERS = new Counter[6]; - - @BeforeEach - void findStatusMetrics() { - 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"))); - } - } - - @Test - void checkStatusMetrics() { - // intermediate responses are not "full" responses and since JDK 20 they are not returned by the client at all - // 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(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 deleted file mode 100644 index 3b0237335a6..00000000000 --- a/examples/microprofile/http-status-count-mp/src/test/resources/application.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# -# Copyright (c) 2022, 2023 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. -# - -security: - enabled: false \ No newline at end of file diff --git a/examples/microprofile/idcs/README.md b/examples/microprofile/idcs/README.md deleted file mode 100644 index 2ac3ecbacc7..00000000000 --- a/examples/microprofile/idcs/README.md +++ /dev/null @@ -1,54 +0,0 @@ -# Helidon MP IDCS - -This example demonstrates integration with IDCS (Oracle identity service, integrated with Open ID Connect provider) where JAX-RS application resources are protected by IDCS. - -## Contents - -This project contains two samples, one (IdcsApplication.java) and a second (ReactiveService.java). It also contains a static resource. When configured the example exposes multiple HTTP endpoints. - -### IDCS Configuration - -[This documentation](https://docs.oracle.com/en/cloud/paas/identity-cloud/uaids/oracle-identity-cloud-service.html#GUID-BC4769EE-258A-4B53-AED5-6BA9888C8275) describes basics of IDCS as well as how you can get IDCS instance. - -1. [Log in to the IDCS console](https://docs.oracle.com/en/cloud/paas/identity-cloud/uaids/how-access-oracle-identity-cloud-service.html) and create a new application of type "confidential app" -2. Within **Resources** - 1. Create two resources called `first_scope` and `second_scope` - 2. Primary Audience = `http://localhost:7987/"` (ensure there is a trailing /) -3. Within **Client Configuration** - 1. Register a client - 2. Allowed Grant Types = Client Credentials,JWT Assertion, Refresh Token, Authorization Code - 3. Check "Allow non-HTTPS URLs" - 4. Set Redirect URL to `http://localhost:7987/oidc/redirect` - 5. Client Type = Confidential - 6. Add all Scopes defined in the resources section - 7. Set allowed operations to `Introspect` - 8. Set Post Logout Redirect URL to `http://localhost:7987/loggedout` - -Ensure you save and *activate* the application - -### Application Configuration - -Edit application.yaml based on your IDCS Configuration - -1. idcs-uri : Base URL of your idcs instance, usually something like https://idcs-.identity.oraclecloud.com -2. idcs-client-id : This is obtained from your IDCS application in the IDCS console -3. idcs-client-secret : This is obtained from your IDCS application in the IDCS console -4. frontend-uri : This is the base URL of your application when run, e.g. `http://localhost:7987` -5. proxy-host : Your proxy server if needed -6. scope-audience : This is the scope audience which MUST match the primary audience in the IDCS resource, recommendation is not to have a trailing slash (/) - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-microprofile-security-idcs.jar -``` - -Try the endpoints: - -| Endpoint | Description | -|:--------------------|:-----------------------------------------------------------------------| -| `rest/login` | Login | -| `rest/scopes` | Full security with scopes and roles (see IdcsResource.java) | -| `rest/service` | Protected service (see application.yaml - security.web-server) | -| `web/resource.html` | Protected static resource (see application.yaml - security.web-server) | diff --git a/examples/microprofile/idcs/pom.xml b/examples/microprofile/idcs/pom.xml deleted file mode 100644 index 6b4fb1982cf..00000000000 --- a/examples/microprofile/idcs/pom.xml +++ /dev/null @@ -1,85 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.microprofile - helidon-examples-microprofile-security-idcs - Helidon Examples Microprofile IDCS Security - - - Microprofile example with IDCS integration (through Open ID Connect) - - - - io.helidon.examples.microprofile.security.idcs.IdcsMain - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.microprofile - helidon-microprofile-oidc - - - io.helidon.security.providers - helidon-security-providers-idcs-mapper - - - io.smallrye - jandex - runtime - true - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/IdcsApplication.java b/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/IdcsApplication.java deleted file mode 100644 index ea7749440ea..00000000000 --- a/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/IdcsApplication.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2018, 2021 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.microprofile.security.idcs; - -import java.util.Set; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.ws.rs.ApplicationPath; -import jakarta.ws.rs.core.Application; - -/** - * Example JAX-RS application with resources protected by IDCS. - */ -@ApplicationScoped -@ApplicationPath("/rest") -public class IdcsApplication extends Application { - @Override - public Set> getClasses() { - return Set.of(IdcsResource.class); - } -} diff --git a/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/IdcsMain.java b/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/IdcsMain.java deleted file mode 100644 index 83da474d4dc..00000000000 --- a/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/IdcsMain.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.microprofile.security.idcs; - -import io.helidon.microprofile.server.Server; - -/** - * IDCS example. - */ -public final class IdcsMain { - private IdcsMain() { - } - - /** - * Start the server and use the application picked up by CDI. - * - * @param args command line arguments, ignored - */ - public static void main(String[] args) { - Server.create().start(); - - System.out.println("Endpoints:"); - System.out.println("Login"); - System.out.println(" http://localhost:7987/rest/login"); - System.out.println("Full security with scopes and roles (see IdcsResource.java)"); - System.out.println(" http://localhost:7987/rest/scopes"); - System.out.println("A protected service (see application.yaml - security.web-server)"); - System.out.println(" http://localhost:7987/service"); - System.out.println("A protected static resource (see application.yaml - security.web-server"); - System.out.println(" http://localhost:7987/web/resource.html"); - } -} diff --git a/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/IdcsResource.java b/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/IdcsResource.java deleted file mode 100644 index f77f27dfc5c..00000000000 --- a/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/IdcsResource.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.microprofile.security.idcs; - -import io.helidon.security.SecurityContext; -import io.helidon.security.abac.role.RoleValidator; -import io.helidon.security.abac.scope.ScopeValidator; -import io.helidon.security.annotations.Authenticated; - -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.QueryParam; -import jakarta.ws.rs.core.Context; -import jakarta.ws.rs.core.Response; - -/** - * JAX-RS resource. - */ -@Path("/") -public class IdcsResource { - /** - * A protected resource (authentication required). - * - * @param context security context that will contain user's subject once login is completed - * @return user's subject as a string - */ - @GET - @Path("/login") - @Authenticated - public String login(@Context SecurityContext context) { - return context.user().toString(); - } - - /** - * A login flow example to use from a HTML frontend. A login button would call this method with a - * query parameter with redirect to the first page. - * - * @param context security context that will contain user's subject once login is completed - * @param redirectTo target URI (relative) to redirect to - * @return redirect response - */ - @GET - @Path("/login2") - @Authenticated - public Response login(@Context SecurityContext context, @QueryParam("target") String redirectTo) { - return Response - .status(Response.Status.TEMPORARY_REDIRECT) - .header("Location", redirectTo) - .build(); - } - - /** - * Authenticated and authorized endpoint that requires two scopes (these must be configure in your IDCS application). - * - * @param context security context - * @return current user's subject as a string, should now contain the scopes required - */ - @GET - @Path("/scopes") - @Authenticated - // Scopes defined in IDCS in my scope audience (see application.yaml) - @ScopeValidator.Scope("first_scope") - @ScopeValidator.Scope("second_scope") - // A group defined in my IDCS domain - @RoleValidator.Roles("my_admins") - public String scopes(@Context SecurityContext context) { - return context.user().toString(); - } -} diff --git a/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/ServiceImpl.java b/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/ServiceImpl.java deleted file mode 100644 index 4352cf6ffee..00000000000 --- a/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/ServiceImpl.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.microprofile.security.idcs; - -import io.helidon.microprofile.server.RoutingPath; -import io.helidon.security.Principal; -import io.helidon.security.SecurityContext; -import io.helidon.security.Subject; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -import jakarta.enterprise.context.ApplicationScoped; - -/** - * Service implementation. - */ -@ApplicationScoped -@RoutingPath("/service") -public class ServiceImpl implements HttpService { - - @Override - public void routing(HttpRules rules) { - rules.get(this::hello); - } - - private void hello(ServerRequest req, ServerResponse res) { - String username = req.context() - .get(SecurityContext.class) - .flatMap(SecurityContext::user) - .map(Subject::principal) - .map(Principal::getName) - .orElse("not authenticated"); - - res.send("Hello from service, you are " + username); - } -} diff --git a/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/package-info.java b/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/package-info.java deleted file mode 100644 index 89aeb0c5644..00000000000 --- a/examples/microprofile/idcs/src/main/java/io/helidon/examples/microprofile/security/idcs/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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 of integration with IDCS (through Open ID Connect). - */ -package io.helidon.examples.microprofile.security.idcs; diff --git a/examples/microprofile/idcs/src/main/resources/META-INF/beans.xml b/examples/microprofile/idcs/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 1b3fbc297cb..00000000000 --- a/examples/microprofile/idcs/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/microprofile/idcs/src/main/resources/WEB/resource.html b/examples/microprofile/idcs/src/main/resources/WEB/resource.html deleted file mode 100644 index 5a16aacbe99..00000000000 --- a/examples/microprofile/idcs/src/main/resources/WEB/resource.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - -Hello, this is a static resource loaded from classpath. -

      - The configuration (microprofile config, accessed from application.yaml): -

      
      -        server.static.classpath.location=/WEB
      -        server.static.classpath.context=/web
      -    
      -

      - - - diff --git a/examples/microprofile/idcs/src/main/resources/application.yaml b/examples/microprofile/idcs/src/main/resources/application.yaml deleted file mode 100644 index 44f5084842f..00000000000 --- a/examples/microprofile/idcs/src/main/resources/application.yaml +++ /dev/null @@ -1,63 +0,0 @@ -# -# Copyright (c) 2018, 2024 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. -# - -# Security requires Helidon config - -server: - port: 7987 - # location on classpath (e.g. src/main/resources/WEB in maven) - static.classpath: - location: "/WEB" - # this is optional, defaults to "/" - context: "/web" -security: - config.require-encryption: false - properties: - # This is a nice way to be able to override this with local properties or env-vars - idcs-uri: "https://tenant-id.identity.oracle.com" - idcs-client-id: "client-id" - idcs-client-secret: "changeit" - # Used as a base for redirects back to us - frontend-uri: "http://localhost:7987" - proxy-host: "if you need proxy" - providers: - - abac: - # Adds ABAC Provider - it does not require any configuration - - oidc: - client-id: "${security.properties.idcs-client-id}" - client-secret: "${security.properties.idcs-client-secret}" - identity-uri: "${security.properties.idcs-uri}" - # A prefix used for custom scopes - scope-audience: "http://localhost:7987/test-application" - proxy-host: "${security.properties.proxy-host}" - frontend-uri: "${security.properties.frontend-uri}" - # We want to redirect to login page (and token can be received either through cookie or header) - redirect: true - - idcs-role-mapper: - multitenant: false - oidc-config: - # we must repeat IDCS configuration, as in this case - # IDCS serves both as open ID connect authenticator and - # as a role mapper. Using minimal configuration here - client-id: "${security.properties.idcs-client-id}" - client-secret: "${security.properties.idcs-client-secret}" - identity-uri: "${security.properties.idcs-uri}" - web-server: - paths: - - path: "/web[/{*}]" - authenticate: true - - path: "/service[/{*}]" - authenticate: true diff --git a/examples/microprofile/idcs/src/main/resources/logging.properties b/examples/microprofile/idcs/src/main/resources/logging.properties deleted file mode 100644 index 7e09243e77e..00000000000 --- a/examples/microprofile/idcs/src/main/resources/logging.properties +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) 2018, 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. -# - -handlers=io.helidon.logging.jul.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=[%1$tc] %4$s: %2$s - %5$s %6$s%n -.level=INFO -AUDIT.level=FINEST -io.helidon.security.providers.oidc.level=FINEST -io.helidon.microprofile.config.level=FINEST diff --git a/examples/microprofile/lra/README.md b/examples/microprofile/lra/README.md deleted file mode 100644 index 41e38cb4308..00000000000 --- a/examples/microprofile/lra/README.md +++ /dev/null @@ -1,50 +0,0 @@ -# Helidon LRA Example - -## Build and run - -```shell -mvn package -java -jar ./target/helidon-examples-microprofile-lra.jar -``` - -### Coordinator -Narayana like coordinator is expected to be running on the port `8070`, url can be changed in application.yaml -```yaml -mp.lra.coordinator.url: http://localhost:8070/lra-coordinator -``` - -#### Build and run LRA coordinator -> :warning: **Experimental feature**: Helidon LRA coordinator is an experimental tool, running it in production is not advised - -```shell -docker build -t helidon/lra-coordinator https://github.com/oracle/helidon.git#:lra/coordinator/server -docker run --rm --name lra-coordinator --network="host" helidon/lra-coordinator -``` - -### Test LRA resource -Then call for completed transaction: -```shell -curl -X PUT -d 'lra rocks' http://localhost:7001/example/start-example -``` -And observe processing success in the output followed by complete called by LRA coordinator: -``` -Data lra rocks processed 🏭 -LRA id: f120a842-88da-429b-82d9-7274ee9ce8f6 completed 🎉 -``` - -For compensated transaction: -```shell -curl -X PUT -d BOOM http://localhost:7001/example/start-example -``` -Observe exception in the output followed by compensation called by LRA coordinator: -``` -java.lang.RuntimeException: BOOM 💥 - at io.helidon.microprofile.example.lra.LRAExampleResource.startExample(LRAExampleResource.java:56) -... -LRA id: 3629421b-b2a4-4fc4-a2f0-941cbf3fa8ad compensated 🚒 -``` - -Or compensated transaction timeout: -```shell -curl -X PUT -d TIMEOUT http://localhost:7001/example/start-example -``` \ No newline at end of file diff --git a/examples/microprofile/lra/pom.xml b/examples/microprofile/lra/pom.xml deleted file mode 100644 index 3c34f49cc29..00000000000 --- a/examples/microprofile/lra/pom.xml +++ /dev/null @@ -1,85 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.microprofile - helidon-examples-microprofile-lra - Helidon Examples Microprofile LRA - - - Microprofile Long Running Actions Example - - - - - io.helidon.microprofile.bundles - helidon-microprofile-core - - - io.helidon.microprofile.config - helidon-microprofile-config - - - io.helidon.microprofile.lra - helidon-microprofile-lra - - - io.helidon.lra - helidon-lra-coordinator-narayana-client - - - io.smallrye - jandex - runtime - true - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/microprofile/lra/src/main/java/io/helidon/microprofile/example/lra/LRAExampleResource.java b/examples/microprofile/lra/src/main/java/io/helidon/microprofile/example/lra/LRAExampleResource.java deleted file mode 100644 index 9381cd77e9c..00000000000 --- a/examples/microprofile/lra/src/main/java/io/helidon/microprofile/example/lra/LRAExampleResource.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.microprofile.example.lra; - -import java.net.URI; -import java.time.temporal.ChronoUnit; -import java.util.logging.Level; -import java.util.logging.Logger; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.ws.rs.HeaderParam; -import jakarta.ws.rs.PUT; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.core.Response; -import org.eclipse.microprofile.lra.LRAResponse; -import org.eclipse.microprofile.lra.annotation.Compensate; -import org.eclipse.microprofile.lra.annotation.Complete; -import org.eclipse.microprofile.lra.annotation.ws.rs.LRA; - -import static org.eclipse.microprofile.lra.annotation.ws.rs.LRA.LRA_HTTP_CONTEXT_HEADER; - -/** - * Example resource with LRA. - */ -@Path("/example") -@ApplicationScoped -public class LRAExampleResource { - - private static final Logger LOGGER = Logger.getLogger(LRAExampleResource.class.getName()); - - /** - * Starts a new long-running action. - * - * @param lraId id of this action - * @param data entity - * @return empty response - * - * @throws InterruptedException this method is sleeping on thread, so it can throw interrupted exception - */ - @PUT - @LRA(value = LRA.Type.REQUIRES_NEW, timeLimit = 500, timeUnit = ChronoUnit.MILLIS) - @Path("start-example") - public Response startExample(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) URI lraId, - String data) throws InterruptedException { - if (data.contains("BOOM")) { - throw new RuntimeException("BOOM 💥"); - } - - if (data.contains("TIMEOUT")) { - Thread.sleep(2000); - } - - LOGGER.info("Data " + data + " processed 🏭"); - return Response.ok().build(); - } - - /** - * Completes the long-running action. - * - * @param lraId id of this action - * @return completed response - */ - @PUT - @Complete - @Path("complete-example") - public Response completeExample(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) URI lraId) { - LOGGER.log(Level.INFO, "LRA id: {0} completed 🎉", lraId); - return LRAResponse.completed(); - } - - /** - * Compensation for long-running action. - * - * @param lraId id of action to compensate - * @return compensated response - */ - @PUT - @Compensate - @Path("compensate-example") - public Response compensateExample(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) URI lraId) { - LOGGER.log(Level.SEVERE, "LRA id: {0} compensated 🚒", lraId); - return LRAResponse.compensated(); - } - -} diff --git a/examples/microprofile/lra/src/main/java/io/helidon/microprofile/example/lra/package-info.java b/examples/microprofile/lra/src/main/java/io/helidon/microprofile/example/lra/package-info.java deleted file mode 100644 index 35125f590af..00000000000 --- a/examples/microprofile/lra/src/main/java/io/helidon/microprofile/example/lra/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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. - */ - -/** - * Helidon MicroProfile LRA Example. - */ -package io.helidon.microprofile.example.lra; - diff --git a/examples/microprofile/lra/src/main/resources/META-INF/beans.xml b/examples/microprofile/lra/src/main/resources/META-INF/beans.xml deleted file mode 100644 index dbf3e648c1e..00000000000 --- a/examples/microprofile/lra/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/microprofile/lra/src/main/resources/application.yaml b/examples/microprofile/lra/src/main/resources/application.yaml deleted file mode 100644 index 7fdbb8cce77..00000000000 --- a/examples/microprofile/lra/src/main/resources/application.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# -# Copyright (c) 2021 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: 7001 - -mp.lra: - coordinator.url: http://localhost:8070/lra-coordinator diff --git a/examples/microprofile/lra/src/main/resources/logging.properties b/examples/microprofile/lra/src/main/resources/logging.properties deleted file mode 100644 index 98447119f24..00000000000 --- a/examples/microprofile/lra/src/main/resources/logging.properties +++ /dev/null @@ -1,19 +0,0 @@ -# -# Copyright (c) 2021, 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. -# - -handlers=io.helidon.logging.jul.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=[%1$tc] %4$s: %2$s - %5$s %6$s%n -.level=INFO diff --git a/examples/microprofile/messaging-sse/README.md b/examples/microprofile/messaging-sse/README.md deleted file mode 100644 index 11f1719b286..00000000000 --- a/examples/microprofile/messaging-sse/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Helidon Reactive Messaging Example - - Example showing - * [Microprofile Reactive Messaging](https://github.com/eclipse/microprofile-reactive-messaging) - with [Microprofile Reactive Stream Operators](https://github.com/eclipse/microprofile-reactive-streams-operators) - connected to [Server-Sent Events](https://eclipse-ee4j.github.io/jersey.github.io/documentation/latest/sse.html). - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-microprofile-messaging-sse.jar -``` - -Then try in the browser: - -http://localhost:7001 \ No newline at end of file diff --git a/examples/microprofile/messaging-sse/pom.xml b/examples/microprofile/messaging-sse/pom.xml deleted file mode 100644 index f3fe7809a59..00000000000 --- a/examples/microprofile/messaging-sse/pom.xml +++ /dev/null @@ -1,104 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.microprofile - helidon-examples-microprofile-messaging-sse - Helidon Examples Microprofile Messaging with SSE - - - Microprofile Reactive Messaging with Server-Sent Events example - - - - - io.helidon.microprofile.messaging - helidon-microprofile-messaging - - - io.helidon.microprofile.bundles - helidon-microprofile - - - org.glassfish.jersey.media - jersey-media-sse - - - io.smallrye - jandex - runtime - true - - - - - - - org.apache.maven.plugins - maven-resources-plugin - - - snippet - - resources - - - - - src/main/java/io/helidon/microprofile/example/messaging/sse - - MsgProcessingBean.java - - - - ${project.build.directory}/classes/WEB - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/microprofile/messaging-sse/src/main/java/io/helidon/microprofile/example/messaging/sse/MessagingExampleResource.java b/examples/microprofile/messaging-sse/src/main/java/io/helidon/microprofile/example/messaging/sse/MessagingExampleResource.java deleted file mode 100644 index 52fd3571c22..00000000000 --- a/examples/microprofile/messaging-sse/src/main/java/io/helidon/microprofile/example/messaging/sse/MessagingExampleResource.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.microprofile.example.messaging.sse; - -import jakarta.enterprise.context.RequestScoped; -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.Context; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.sse.Sse; -import jakarta.ws.rs.sse.SseEventSink; - -/** - * Example resource with SSE. - */ -@Path("example") -@RequestScoped -public class MessagingExampleResource { - private final MsgProcessingBean msgBean; - - /** - * Constructor injection of field values. - * - * @param msgBean Messaging example bean - */ - @Inject - public MessagingExampleResource(MsgProcessingBean msgBean) { - this.msgBean = msgBean; - } - - - /** - * Process send. - * @param msg message to process - */ - @Path("/send/{msg}") - @GET - @Produces(MediaType.APPLICATION_JSON) - public void getSend(@PathParam("msg") String msg) { - msgBean.process(msg); - } - - /** - * Consume event. - * - * @param eventSink sink - * @param sse event - */ - @GET - @Path("sse") - @Produces(MediaType.SERVER_SENT_EVENTS) - public void listenToEvents(@Context SseEventSink eventSink, @Context Sse sse) { - msgBean.addSink(eventSink, sse); - } -} diff --git a/examples/microprofile/messaging-sse/src/main/java/io/helidon/microprofile/example/messaging/sse/MsgProcessingBean.java b/examples/microprofile/messaging-sse/src/main/java/io/helidon/microprofile/example/messaging/sse/MsgProcessingBean.java deleted file mode 100644 index 9112f5ed778..00000000000 --- a/examples/microprofile/messaging-sse/src/main/java/io/helidon/microprofile/example/messaging/sse/MsgProcessingBean.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.microprofile.example.messaging.sse; - -import java.util.concurrent.SubmissionPublisher; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.ws.rs.sse.OutboundSseEvent; -import jakarta.ws.rs.sse.Sse; -import jakarta.ws.rs.sse.SseBroadcaster; -import jakarta.ws.rs.sse.SseEventSink; -import org.eclipse.microprofile.reactive.messaging.Incoming; -import org.eclipse.microprofile.reactive.messaging.Outgoing; -import org.eclipse.microprofile.reactive.streams.operators.ProcessorBuilder; -import org.eclipse.microprofile.reactive.streams.operators.ReactiveStreams; -import org.glassfish.jersey.media.sse.OutboundEvent; -import org.reactivestreams.FlowAdapters; -import org.reactivestreams.Publisher; - -/** - * Bean for message processing. - */ -@ApplicationScoped -public class MsgProcessingBean { - private final SubmissionPublisher emitter = new SubmissionPublisher<>(); - private SseBroadcaster sseBroadcaster; - - /** - * Create a publisher for the emitter. - * - * @return A Publisher from the emitter - */ - @Outgoing("multiplyVariants") - public Publisher preparePublisher() { - // Create new publisher for emitting to by this::process - return ReactiveStreams - .fromPublisher(FlowAdapters.toPublisher(emitter)) - .buildRs(); - } - - /** - * Returns a builder for a processor that maps a string into three variants. - * - * @return ProcessorBuilder - */ - @Incoming("multiplyVariants") - @Outgoing("wrapSseEvent") - public ProcessorBuilder multiply() { - // Multiply to 3 variants of same message - return ReactiveStreams.builder() - .flatMap(o -> - ReactiveStreams.of( - // upper case variant - o.toUpperCase(), - // repeat twice variant - o.repeat(2), - // reverse chars 'tnairav' - new StringBuilder(o).reverse().toString()) - ); - } - - /** - * Maps a message to an sse event. - * - * @param msg to wrap - * @return an outbound SSE event - */ - @Incoming("wrapSseEvent") - @Outgoing("broadcast") - public OutboundSseEvent wrapSseEvent(String msg) { - // Map every message to sse event - return new OutboundEvent.Builder().data(msg).build(); - } - - /** - * Broadcasts an event. - * - * @param sseEvent Event to broadcast - */ - @Incoming("broadcast") - public void broadcast(OutboundSseEvent sseEvent) { - // Broadcast to all sse sinks - this.sseBroadcaster.broadcast(sseEvent); - } - - /** - * Consumes events. - * - * @param eventSink event sink - * @param sse event - */ - public void addSink(final SseEventSink eventSink, final Sse sse) { - if (this.sseBroadcaster == null) { - this.sseBroadcaster = sse.newBroadcaster(); - } - this.sseBroadcaster.register(eventSink); - } - - /** - * Emit a message. - * - * @param msg message to emit - */ - public void process(final String msg) { - emitter.submit(msg); - } -} diff --git a/examples/microprofile/messaging-sse/src/main/java/io/helidon/microprofile/example/messaging/sse/package-info.java b/examples/microprofile/messaging-sse/src/main/java/io/helidon/microprofile/example/messaging/sse/package-info.java deleted file mode 100644 index 8cee458fbdc..00000000000 --- a/examples/microprofile/messaging-sse/src/main/java/io/helidon/microprofile/example/messaging/sse/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2020 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. - */ - -/** - * Helidon MicroProfile Messaging Example. - */ -package io.helidon.microprofile.example.messaging.sse; - diff --git a/examples/microprofile/messaging-sse/src/main/resources/META-INF/beans.xml b/examples/microprofile/messaging-sse/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 4a5ec955fb7..00000000000 --- a/examples/microprofile/messaging-sse/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/microprofile/messaging-sse/src/main/resources/WEB/favicon.ico b/examples/microprofile/messaging-sse/src/main/resources/WEB/favicon.ico deleted file mode 100644 index d91659fdb53c934af789e9b93e2d92c679f975d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1230 zcmV;<1Tp)GP)*8l(j8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H11WQRoK~z|Uy_Z{T6lE00e`jX8mqMWtT1?w51zW;RQDQ<{=()Hdzz zw!1sW2fMg*x83dr`hWW7ob&&FCuhEyofXfTJ#V90OB%YTYYw|#iqKDJj0GMwK@Y%Lzb*2G_bGtSTx(vr7!0A-X zHY!8QihhFz^yc-LWJMPj_pR+MShshrgzV#hCzVZx^mxsF+CGF=0g7G^6xo&($5mbY zRU=mL$Bvzg{1cN{v^qesy}_f-QEV5Pufbps^#z|0E2J zJyz}e*Pm0dHv$96aq&}Dc-QIF?TMP7ook+Zwz{~M`igKuIKUO}#-k`(0XumEaWYG1 zxfWQ4oQVxi%aZoGC63%h^D_sdv4n5{-+}5+6kbjPjv=^9XFKynxC}7K!Hw-JUA7_Q z+)_8%CRg@Xzp3!vh!A7s!|gQXuF?{h>9p{@R_W@r42p)=SP6W$Hc<9MUBQV5@k8F-Od+!DwicL++HXZpB zC>zZl3`18KfDYSW!={DO8_kV6_NXo&tq5jB2G*gRNnRbVz7S`AxlUu1Z1memKcl6e@BcFUqZIhcm4*geIb?&ONqhXK8GBAj}^Zx{0VTbCj)n4Q0uQ@WOY3GbL<) z4%~OMZLl?FTJv)B(5m^FE27uGo$Wf+`qR~JkfcvhC=~8aSTtitV5uFpcLBN4SYEbu za$=_8ztA~&bCdx!9ntmCFVD8LwzMq*%w*sp*>U&0XotVnRy}M8lMAL;Cjh;-Fyq)9 zPsW1|6E#io=VeCs3=S+l1BWlMtO?K|y>C7OHf>NCK>gxNa_|4+r0 z&65W0&@qMkW5V{hzyUlfzsOTVTLhUNh2P<^|1aOc>Q2L8Ezli}jT;=Gecy(kQ8oa< safbu=4pe_F$QIK3H*|aCS+%?NUyMb7$(BA=Gynhq07*qoM6N<$f|!R&8~^|S diff --git a/examples/microprofile/messaging-sse/src/main/resources/WEB/img/arrow-1.png b/examples/microprofile/messaging-sse/src/main/resources/WEB/img/arrow-1.png deleted file mode 100644 index bbba0aef8a6ce9efc80b64f1820f5eb38d83a209..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18222 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 L($S*M>{`;laxc~L diff --git a/examples/microprofile/messaging-sse/src/main/resources/WEB/img/frank.png b/examples/microprofile/messaging-sse/src/main/resources/WEB/img/frank.png deleted file mode 100644 index 51a13d8db8bc02ad1613da3b809cff394462a77a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10516 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 - - - - - - Helidon Reactive Messaging - - - - - - - - -
      -
      -
      - -
      -
      Send
      -
      -
      -
      -
      -
      REST call /example/send/{msg}
      -
      -
      -
      SSE messages received
      -
      -
      -
      -
      -
      -            
      -        
      -
      -
      - - - - - \ No newline at end of file diff --git a/examples/microprofile/messaging-sse/src/main/resources/WEB/main.css b/examples/microprofile/messaging-sse/src/main/resources/WEB/main.css deleted file mode 100644 index d4073f5e172..00000000000 --- a/examples/microprofile/messaging-sse/src/main/resources/WEB/main.css +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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. - */ - -#root { - background-color: #36ABF2; - font-family: Roboto,sans-serif; - color: #fff; - position: absolute; - overflow-x: hidden; - -ms-overflow-style: none; /* Internet Explorer 10+ */ - scrollbar-width: none; /* Firefox */ - top: 0; - left: 0; - width: 100%; - height: 100%; -} -#root::-webkit-scrollbar { - display: none; /* Safari and Chrome */ -} - -#helidon { - width: 509px; - height: 273px; - position: relative; - left: -509px; - z-index: 4; - background: url('img/frank.png'); -} - -#rest-tip { - position: relative; - top: -80px; - left: 160px; -} - -#rest-tip-arrow { - width: 205px; - height: 304px; - z-index: 4; - top: -20px; - background: url('img/arrow-1.png'); -} -#rest-tip-label { - position: absolute; - white-space: nowrap; - font-size: 18px; - font-weight: bold; - z-index: 4; - left: -60px; -} - -#sse-tip { - position: absolute; - overflow: hidden; - display: flex; - width: auto; - height: auto; - top: 5%; - right: 10%; - z-index: 0; -} - -#sse-tip-arrow { - position: relative; - top: -30px; - width: 296px; - height: 262px; - z-index: 4; - background: url('img/arrow-2.png'); -} -#sse-tip-label { - position: relative; - white-space: nowrap; - font-size: 18px; - font-weight: bold; - z-index: 4; -} - -#producer { - float: left; - position: relative; - width: 300px; - height: 100%; - margin: 50px; - padding: 10px; - z-index: 99; -} - -#msgBox { - position: absolute; - width: 300px; - top: 25%; - right: 3%; - height: 100%; - margin: 50px; - padding: 10px; - z-index: 20; -} - -#input { - width: 210px; - height: 22px; - top: 58px; - left: 30px; - background-color: white; - border-radius: 10px; - border-style: solid; - border-color: white; - position: absolute; - z-index: 10; -} - -#inputCloud { - position: relative; - width: 310px; - height: 150px; - background: url('img/cloud.png'); -} - -#msg { - background-color: #D2EBFC; - color: #1A9BF4; - border-radius: 10px; - width: 300px; - height: 50px; - margin: 5px; - display: flex; - padding-left: 10px; - justify-content: center; - align-items: center; - z-index: 99; -} - -#submit { - font-weight: bold; - background-color: aqua; - color: #1A9BF4; - border-radius: 12px; - width: 100px; - height: 30px; - display: flex; - justify-content: center; - align-items: center; - margin: 5px; - cursor: pointer; -} - -#snippet { - position: absolute; - top: 15%; - left: 30%; - width: 40%; - z-index: 5; -} - -.hljs { - border-radius: 10px; - font-size: 12px; -} \ No newline at end of file diff --git a/examples/microprofile/messaging-sse/src/main/resources/application.yaml b/examples/microprofile/messaging-sse/src/main/resources/application.yaml deleted file mode 100644 index c19b8a3f591..00000000000 --- a/examples/microprofile/messaging-sse/src/main/resources/application.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# -# Copyright (c) 2020 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: 7001 -server.static.classpath.location: /WEB -server.static.classpath.welcome: index.html diff --git a/examples/microprofile/messaging-sse/src/main/resources/logging.properties b/examples/microprofile/messaging-sse/src/main/resources/logging.properties deleted file mode 100644 index c5729141913..00000000000 --- a/examples/microprofile/messaging-sse/src/main/resources/logging.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2020, 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. -# - -handlers=io.helidon.logging.jul.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=[%1$tc] %4$s: %2$s - %5$s %6$s%n -.level=INFO -io.helidon.microprofile.config.level=FINEST diff --git a/examples/microprofile/multipart/README.md b/examples/microprofile/multipart/README.md deleted file mode 100644 index 58aea2ba671..00000000000 --- a/examples/microprofile/multipart/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# MicroProfile MultiPart Example - -This example demonstrates how to use the Jersey `MultiPartFeature` with Helidon. - -This project implements a simple file service web application that supports uploading - and downloading files. The unit test uses the JAXRS client API to test the endpoints. - -## Build - -```shell -mvn package -``` - -## Run - -First, start the server: - -```shell -java -jar target/helidon-examples-microprofile-multipart.jar -``` - -Then open in your browser. diff --git a/examples/microprofile/multipart/pom.xml b/examples/microprofile/multipart/pom.xml deleted file mode 100644 index dbc1e2f25ed..00000000000 --- a/examples/microprofile/multipart/pom.xml +++ /dev/null @@ -1,94 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.microprofile - helidon-examples-microprofile-multipart - Helidon Examples Microprofile Multipart - - - Example of a form based file upload with Helidon MP. - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - org.glassfish.jersey.media - jersey-media-multipart - - - io.helidon.logging - helidon-logging-jul - runtime - - - io.smallrye - jandex - runtime - true - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.microprofile.testing - helidon-microprofile-testing-junit5 - test - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/microprofile/multipart/src/main/java/io/helidon/examples/microprofile/multipart/FileService.java b/examples/microprofile/multipart/src/main/java/io/helidon/examples/microprofile/multipart/FileService.java deleted file mode 100644 index 42475e9eedf..00000000000 --- a/examples/microprofile/multipart/src/main/java/io/helidon/examples/microprofile/multipart/FileService.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2021 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.microprofile.multipart; - -import java.io.IOException; -import java.net.URI; -import java.nio.file.Files; -import java.nio.file.StandardCopyOption; -import java.util.Map; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import jakarta.json.Json; -import jakarta.json.JsonArrayBuilder; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -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 jakarta.ws.rs.core.StreamingOutput; -import org.glassfish.jersey.media.multipart.BodyPart; -import org.glassfish.jersey.media.multipart.BodyPartEntity; -import org.glassfish.jersey.media.multipart.MultiPart; - -/** - * File service. - */ -@Path("/api") -@ApplicationScoped -public class FileService { - - private static final JsonBuilderFactory JSON_FACTORY = Json.createBuilderFactory(Map.of()); - - private final FileStorage storage; - - @Inject - FileService(FileStorage storage) { - this.storage = storage; - } - - /** - * Upload a file to the storage. - * @param multiPart multipart entity - * @return Response - * @throws IOException if an IO error occurs - */ - @POST - @Consumes(MediaType.MULTIPART_FORM_DATA) - public Response upload(MultiPart multiPart) throws IOException { - for (BodyPart part : multiPart.getBodyParts()) { - if ("file[]".equals(part.getContentDisposition().getParameters().get("name"))) { - Files.copy(part.getEntityAs(BodyPartEntity.class).getInputStream(), - storage.create(part.getContentDisposition().getFileName()), - StandardCopyOption.REPLACE_EXISTING); - } - } - return Response.seeOther(URI.create("ui")).build(); - } - - /** - * Download a file from the storage. - * @param fname file name of the file to download - * @return Response - */ - @GET - @Path("{fname}") - @Produces(MediaType.APPLICATION_OCTET_STREAM) - public Response download(@PathParam("fname") String fname) { - return Response.ok() - .header("Content-Disposition", "attachment; filename=\"" + fname + "\"") - .entity((StreamingOutput) output -> Files.copy(storage.lookup(fname), output)) - .build(); - } - - /** - * List the files in the storage. - * @return JsonObject - */ - @GET - @Produces(MediaType.APPLICATION_JSON) - public JsonObject list() { - JsonArrayBuilder arrayBuilder = JSON_FACTORY.createArrayBuilder(); - storage.listFiles().forEach(arrayBuilder::add); - return JSON_FACTORY.createObjectBuilder().add("files", arrayBuilder).build(); - } -} diff --git a/examples/microprofile/multipart/src/main/java/io/helidon/examples/microprofile/multipart/FileStorage.java b/examples/microprofile/multipart/src/main/java/io/helidon/examples/microprofile/multipart/FileStorage.java deleted file mode 100644 index e0ae1f77980..00000000000 --- a/examples/microprofile/multipart/src/main/java/io/helidon/examples/microprofile/multipart/FileStorage.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2021 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.microprofile.multipart; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.stream.Stream; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.ws.rs.BadRequestException; -import jakarta.ws.rs.NotFoundException; - -/** - * Simple bean to managed a directory based storage. - */ -@ApplicationScoped -public class FileStorage { - - private final Path storageDir; - - /** - * Create a new instance. - */ - public FileStorage() { - try { - storageDir = Files.createTempDirectory("fileupload"); - } catch (IOException ex) { - throw new UncheckedIOException(ex); - } - } - - /** - * Get the storage directory. - * @return directory - */ - public Path storageDir() { - return storageDir; - } - - /** - * Get the names of the files in the storage directory. - * @return Stream of file names - */ - public Stream listFiles() { - try { - return Files.walk(storageDir) - .filter(Files::isRegularFile) - .map(storageDir::relativize) - .map(java.nio.file.Path::toString); - } catch (IOException ex) { - throw new UncheckedIOException(ex); - } - } - - /** - * Create a new file in the storage. - * @param fname file name - * @return file - * @throws BadRequestException if the resolved file is not contained in the storage directory - */ - public Path create(String fname) { - Path file = storageDir.resolve(fname); - if (!file.getParent().equals(storageDir)) { - throw new BadRequestException("Invalid file name"); - } - return file; - } - - /** - * Lookup an existing file in the storage. - * @param fname file name - * @return file - * @throws NotFoundException If the resolved file does not exist - * @throws BadRequestException if the resolved file is not contained in the storage directory - */ - public Path lookup(String fname) { - Path file = storageDir.resolve(fname); - if (!file.getParent().equals(storageDir)) { - throw new BadRequestException("Invalid file name"); - } - if (!Files.exists(file)) { - throw new NotFoundException(); - } - if (!Files.isRegularFile(file)) { - throw new BadRequestException("Not a file"); - } - return file; - } -} diff --git a/examples/microprofile/multipart/src/main/java/io/helidon/examples/microprofile/multipart/MultiPartFeatureProvider.java b/examples/microprofile/multipart/src/main/java/io/helidon/examples/microprofile/multipart/MultiPartFeatureProvider.java deleted file mode 100644 index d0fe1fedea6..00000000000 --- a/examples/microprofile/multipart/src/main/java/io/helidon/examples/microprofile/multipart/MultiPartFeatureProvider.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2021 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.microprofile.multipart; - -import jakarta.ws.rs.core.Feature; -import jakarta.ws.rs.core.FeatureContext; -import jakarta.ws.rs.ext.Provider; -import org.glassfish.jersey.media.multipart.MultiPartFeature; - -/** - * {@link MultiPartFeature} is not auto-discovered. This {@link Feature} is discovered with {@link @Provider} - * and registers {@link MultiPartFeature} manually. - */ -@Provider -public class MultiPartFeatureProvider implements Feature { - - @Override - public boolean configure(FeatureContext context) { - return new MultiPartFeature().configure(context); - } -} diff --git a/examples/microprofile/multipart/src/main/java/io/helidon/examples/microprofile/multipart/package-info.java b/examples/microprofile/multipart/src/main/java/io/helidon/examples/microprofile/multipart/package-info.java deleted file mode 100644 index 5efec4db67c..00000000000 --- a/examples/microprofile/multipart/src/main/java/io/helidon/examples/microprofile/multipart/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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. - */ - -/** - * Helidon Examples Microprofile Multipart. - */ -package io.helidon.examples.microprofile.multipart; diff --git a/examples/microprofile/multipart/src/main/resources/META-INF/beans.xml b/examples/microprofile/multipart/src/main/resources/META-INF/beans.xml deleted file mode 100644 index dadaed509ce..00000000000 --- a/examples/microprofile/multipart/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - diff --git a/examples/microprofile/multipart/src/main/resources/META-INF/microprofile-config.properties b/examples/microprofile/multipart/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 08e3983551c..00000000000 --- a/examples/microprofile/multipart/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2021 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. -# - -# Microprofile server properties -server.port=8080 -server.host=0.0.0.0 - -server.static.classpath.location=/WEB -server.static.classpath.welcome=index.html -server.static.classpath.context=/ui diff --git a/examples/microprofile/multipart/src/main/resources/WEB/index.html b/examples/microprofile/multipart/src/main/resources/WEB/index.html deleted file mode 100644 index 47db7b2cbb5..00000000000 --- a/examples/microprofile/multipart/src/main/resources/WEB/index.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - Helidon Examples Microprofile Multipart - - - - - -

      Uploaded files

      -
      - -

      Upload

      -
      - Select a file to upload: - - -
      - - - - \ No newline at end of file diff --git a/examples/microprofile/multipart/src/main/resources/logging.properties b/examples/microprofile/multipart/src/main/resources/logging.properties deleted file mode 100644 index c5299aba06d..00000000000 --- a/examples/microprofile/multipart/src/main/resources/logging.properties +++ /dev/null @@ -1,36 +0,0 @@ -# -# Copyright (c) 2021, 2024 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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.microprofile.level=INFO -#io.helidon.common.level=INFO -#org.glassfish.jersey.level=INFO -#org.jboss.weld=INFO diff --git a/examples/microprofile/multipart/src/test/java/io/helidon/examples/microprofile/multipart/FileServiceTest.java b/examples/microprofile/multipart/src/test/java/io/helidon/examples/microprofile/multipart/FileServiceTest.java deleted file mode 100644 index 1de34916997..00000000000 --- a/examples/microprofile/multipart/src/test/java/io/helidon/examples/microprofile/multipart/FileServiceTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.microprofile.multipart; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; - -import io.helidon.microprofile.server.JaxRsCdiExtension; -import io.helidon.microprofile.server.ServerCdiExtension; -import io.helidon.microprofile.testing.junit5.AddBean; -import io.helidon.microprofile.testing.junit5.AddExtension; -import io.helidon.microprofile.testing.junit5.DisableDiscovery; -import io.helidon.microprofile.testing.junit5.HelidonTest; - -import jakarta.json.JsonObject; -import jakarta.json.JsonString; -import jakarta.ws.rs.client.Entity; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import org.glassfish.jersey.client.ClientProperties; -import org.glassfish.jersey.ext.cdi1x.internal.CdiComponentProvider; -import org.glassfish.jersey.media.multipart.MultiPart; -import org.glassfish.jersey.media.multipart.MultiPartFeature; -import org.glassfish.jersey.media.multipart.file.FileDataBodyPart; -import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; -import org.junit.jupiter.api.io.TempDir; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; - -/** - * Tests {@link FileService}. - */ -@HelidonTest -@DisableDiscovery -@AddExtension(ServerCdiExtension.class) -@AddExtension(JaxRsCdiExtension.class) -@AddExtension(CdiComponentProvider.class) -@AddBean(FileService.class) -@AddBean(FileStorage.class) -@AddBean(MultiPartFeatureProvider.class) -@TestMethodOrder(OrderAnnotation.class) -public class FileServiceTest { - - @Test - @Order(1) - public void testUpload(WebTarget target, @TempDir Path tempDirectory) throws IOException { - File file = Files.write(tempDirectory.resolve("foo.txt"), "bar\n".getBytes(StandardCharsets.UTF_8)).toFile(); - MultiPart multipart = new MultiPart() - .bodyPart(new FileDataBodyPart("file[]", file, MediaType.APPLICATION_OCTET_STREAM_TYPE)); - try (Response response = target - .property(ClientProperties.FOLLOW_REDIRECTS, Boolean.FALSE) - .register(MultiPartFeature.class) - .path("/api") - .request() - .post(Entity.entity(multipart, MediaType.MULTIPART_FORM_DATA_TYPE))) { - assertThat(response.getStatus(), is(303)); - } - } - - @Test - @Order(2) - public void testList(WebTarget target) { - try (Response response = target - .path("/api") - .request(MediaType.APPLICATION_JSON_TYPE) - .get()) { - assertThat(response.getStatus(), is(200)); - JsonObject json = response.readEntity(JsonObject.class); - assertThat(json, is(notNullValue())); - List files = json.getJsonArray("files").getValuesAs(v -> ((JsonString) v).getString()); - assertThat(files, hasItem("foo.txt")); - } - } - - @Test - @Order(3) - public void testDownload(WebTarget target) throws IOException { - try (Response response = target - .register(MultiPartFeature.class) - .path("/api/foo.txt") - .request(MediaType.APPLICATION_OCTET_STREAM_TYPE) - .get()) { - assertThat(response.getStatus(), is(200)); - assertThat(response.getHeaderString("Content-Disposition"), containsString("filename=\"foo.txt\"")); - InputStream inputStream = response.readEntity(InputStream.class); - assertThat(new String(inputStream.readAllBytes(), StandardCharsets.UTF_8), is("bar\n")); - } - } -} \ No newline at end of file diff --git a/examples/microprofile/multiport/README.md b/examples/microprofile/multiport/README.md deleted file mode 100644 index 4ec6b8ae9eb..00000000000 --- a/examples/microprofile/multiport/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# Helidon MicroProfile Multiple Port Example - -It is common when deploying a microservice to run your service on -multiple ports so that you can control the visibility of your -service's endpoints. For example you might want to use three ports: - -- 8080: public REST endpoints of application -- 8081: private REST endpoints of application -- 8082: admin endpoints for health, metrics, etc. - -This lets you expose only the public endpoints via your -ingress controller or load balancer. - -This example shows a Helidon JAX-RS application running on three ports -as described above. - -The ports are configured in `application.yaml` by using named sockets. - -Two Applications are defined, each associated with a different socket -using @RoutingName. - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-microprofile-multiport.jar -``` - -## Exercise the application - -```shell -curl -X GET http://localhost:8080/hello - -curl -X GET http://localhost:8081/private/hello - -curl -X GET http://localhost:8082/health - -curl -X GET http://localhost:8082/metrics -``` diff --git a/examples/microprofile/multiport/pom.xml b/examples/microprofile/multiport/pom.xml deleted file mode 100644 index c2de80db069..00000000000 --- a/examples/microprofile/multiport/pom.xml +++ /dev/null @@ -1,108 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.microprofile - helidon-examples-microprofile-multiport - Helidon Examples Microprofile Multiple Ports - - - - io.helidon.microprofile.bundles - helidon-microprofile-core - - - io.helidon.config - helidon-config-yaml - - - io.helidon.microprofile.metrics - helidon-microprofile-metrics - - - io.helidon.microprofile.health - helidon-microprofile-health - - - io.helidon.webserver.observe - helidon-webserver-observe-metrics - runtime - - - io.helidon.metrics - helidon-metrics-system-meters - runtime - - - io.helidon.logging - helidon-logging-jul - runtime - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - org.junit.jupiter - junit-jupiter-params - test - - - io.helidon.microprofile.testing - helidon-microprofile-testing-junit5 - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - - diff --git a/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PrivateApplication.java b/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PrivateApplication.java deleted file mode 100644 index 6725c1b6366..00000000000 --- a/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PrivateApplication.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2021 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.microprofile.multiport; - -import java.util.Set; - -import io.helidon.microprofile.server.RoutingName; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.ws.rs.core.Application; - -/** - * Application to expose private resource. - */ -@ApplicationScoped -@RoutingName("private") -public class PrivateApplication extends Application { - @Override - public Set> getClasses() { - return Set.of(PrivateResource.class); - } -} diff --git a/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PrivateResource.java b/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PrivateResource.java deleted file mode 100644 index 0d3ecb00c6a..00000000000 --- a/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PrivateResource.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2021 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.microprofile.multiport; - -import jakarta.enterprise.context.RequestScoped; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; - -/** - * Simple resource. - */ -@RequestScoped -@Path("/private") -public class PrivateResource { - - /** - * Return a private worldly greeting message. - * - * @return {@link String} - */ - @Path("/hello") - @GET - public String helloWorld() { - return "Private Hello World!!"; - } -} diff --git a/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PublicApplication.java b/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PublicApplication.java deleted file mode 100644 index 8d1b367d244..00000000000 --- a/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PublicApplication.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2021 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.microprofile.multiport; - -import java.util.Set; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.ws.rs.core.Application; - -/** - * Application to expose public resource. - */ -@ApplicationScoped -public class PublicApplication extends Application { - @Override - public Set> getClasses() { - return Set.of(PublicResource.class); - } -} diff --git a/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PublicResource.java b/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PublicResource.java deleted file mode 100644 index dcc0b2ed928..00000000000 --- a/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/PublicResource.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2021 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.microprofile.multiport; - -import jakarta.enterprise.context.RequestScoped; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; - -/** - * Simple resource. - */ -@RequestScoped -@Path("/") -public class PublicResource { - - /** - * Return a worldly greeting message. - * - * @return {@link String} - */ - @Path("/hello") - @GET - public String helloWorld() { - return "Public Hello World!!"; - } -} diff --git a/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/package-info.java b/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/package-info.java deleted file mode 100644 index f438f5b6510..00000000000 --- a/examples/microprofile/multiport/src/main/java/io/helidon/examples/microprofile/multiport/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2021 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. - */ -/** - * Application that exposes multiple ports. - */ -package io.helidon.examples.microprofile.multiport; diff --git a/examples/microprofile/multiport/src/main/resources/META-INF/beans.xml b/examples/microprofile/multiport/src/main/resources/META-INF/beans.xml deleted file mode 100644 index dbf3e648c1e..00000000000 --- a/examples/microprofile/multiport/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/microprofile/multiport/src/main/resources/application.yaml b/examples/microprofile/multiport/src/main/resources/application.yaml deleted file mode 100644 index 06c6400f7e1..00000000000 --- a/examples/microprofile/multiport/src/main/resources/application.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# -# Copyright (c) 2021, 2023 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: "localhost" - sockets: - - name: "private" - port: 8081 - - name: "admin" - port: 8082 - # bind address is optional, if not defined, server host will be used) - bind-address: "localhost" - features: - observe: - # Metrics and health run on admin port - sockets: "admin" diff --git a/examples/microprofile/multiport/src/main/resources/logging.properties b/examples/microprofile/multiport/src/main/resources/logging.properties deleted file mode 100644 index 3efb53215d0..00000000000 --- a/examples/microprofile/multiport/src/main/resources/logging.properties +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2022, 2023 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 -# Send messages to the console -handlers=io.helidon.logging.jul.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 -io.helidon.level=INFO -io.helidon.faulttolerance.level=INFO - - diff --git a/examples/microprofile/multiport/src/test/java/io/helidon/examples/microprofile/multiport/MainTest.java b/examples/microprofile/multiport/src/test/java/io/helidon/examples/microprofile/multiport/MainTest.java deleted file mode 100644 index 594ca7d6c54..00000000000 --- a/examples/microprofile/multiport/src/test/java/io/helidon/examples/microprofile/multiport/MainTest.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.microprofile.multiport; - -import java.util.List; -import java.util.stream.Stream; - -import io.helidon.microprofile.server.ServerCdiExtension; -import io.helidon.microprofile.testing.junit5.AddConfig; -import io.helidon.microprofile.testing.junit5.HelidonTest; - -import jakarta.inject.Inject; -import jakarta.ws.rs.client.Client; -import jakarta.ws.rs.client.ClientBuilder; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.core.Response.Status; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Unit test for MP multiport example. - */ -@HelidonTest -@AddConfig(key = "server.sockets.0.port", value = "0") // Force ports to be dynamically allocated -@AddConfig(key = "server.sockets.1.port", value = "0") -class MainTest { - // Port names - private static final String ADMIN_PORT = "admin"; - private static final String PRIVATE_PORT = "private"; - private static final String PUBLIC_PORT = "default"; - - private static final String BASE_URL = "http://localhost:"; - - // Used for other (private, admin) ports - private static Client client; - - // Used for the default (public) port which HelidonTest will configure for us - @Inject - private WebTarget publicWebTarget; - - // Needed to get values of dynamically allocated admin and private ports - @Inject - private ServerCdiExtension serverCdiExtension; - - static Stream initParams() { - final String PUBLIC_PATH = "/hello"; - final String PRIVATE_PATH = "/private/hello"; - final String HEALTH_PATH = "/health"; - final String METRICS_PATH = "/metrics"; - - return List.of( - new Params(PUBLIC_PORT, PUBLIC_PATH, Status.OK), - new Params(PUBLIC_PORT, PRIVATE_PATH, Status.NOT_FOUND), - new Params(PUBLIC_PORT, HEALTH_PATH, Status.NOT_FOUND), - new Params(PUBLIC_PORT, METRICS_PATH, Status.NOT_FOUND), - - new Params(PRIVATE_PORT, PUBLIC_PATH, Status.NOT_FOUND), - new Params(PRIVATE_PORT, PRIVATE_PATH, Status.OK), - new Params(PRIVATE_PORT, HEALTH_PATH, Status.NOT_FOUND), - new Params(PRIVATE_PORT, METRICS_PATH, Status.NOT_FOUND), - - new Params(ADMIN_PORT, PUBLIC_PATH, Status.NOT_FOUND), - new Params(ADMIN_PORT, PRIVATE_PATH, Status.NOT_FOUND), - new Params(ADMIN_PORT, HEALTH_PATH, Status.OK), - new Params(ADMIN_PORT, METRICS_PATH, Status.OK) - ).stream(); - } - - @BeforeAll - static void initClass() { - client = ClientBuilder.newClient(); - } - - @AfterAll - static void destroyClass() { - client.close();; - } - - @MethodSource("initParams") - @ParameterizedTest - public void testPortAccess(Params params) { - WebTarget webTarget; - - if (params.portName.equals(PUBLIC_PORT)) { - webTarget = publicWebTarget; - } else { - webTarget = client.target(BASE_URL + serverCdiExtension.port(params.portName)); - } - - try (Response response = webTarget.path(params.path) - .request() - .get()) { - assertThat(webTarget.getUri() + " returned incorrect HTTP status", - response.getStatusInfo().toEnum(), is(params.httpStatus)); - } - } - - @Test - void testEndpoints() { - // Probe PUBLIC port - try (Response response = publicWebTarget.path("/hello") - .request() - .get()) { - assertThat("default port should be serving public resource", - response.getStatusInfo().toEnum(), is(Response.Status.OK)); - assertThat("default port should return public data", - response.readEntity(String.class), is("Public Hello World!!")); - } - - // Probe PRIVATE port - int privatePort = serverCdiExtension.port(PRIVATE_PORT); - WebTarget baseTarget = client.target(BASE_URL + privatePort); - try (Response response = baseTarget.path("/private/hello") - .request() - .get()) { - assertThat("port " + privatePort + " should be serving private resource", - response.getStatusInfo().toEnum(), is(Response.Status.OK)); - assertThat("port " + privatePort + " should return private data", - response.readEntity(String.class), is("Private Hello World!!")); - } - } - - private static class Params { - String portName; - String path; - Response.Status httpStatus; - - private Params(String portName, String path, Response.Status httpStatus) { - this.portName = portName; - this.path = path; - this.httpStatus = httpStatus; - } - - @Override - public String toString() { - return portName + ":" + path + " should return " + httpStatus; - } - } -} diff --git a/examples/microprofile/oci-tls-certificates/README.md b/examples/microprofile/oci-tls-certificates/README.md deleted file mode 100644 index 856840195f7..00000000000 --- a/examples/microprofile/oci-tls-certificates/README.md +++ /dev/null @@ -1,114 +0,0 @@ -# Helidon TLS and OCI Certificate Service Integration Example - -This module contains an example usage of the [OciCertificatesTlsManager](../../../integrations/oci/tls-certificates) provider that offers lifecycle and rotation of certificates to be used with Helidon. - -1. [Prerequisites](#prerequisites) -2. [Setting up OCI](#setting-up-oci) - 1. [Configuration](#configuration) - 2. [Prepare CA(Certification Authority)](#prepare-cacertification-authority) - 3. [Prepare keys and certificates](#prepare-keys-and-certificates) -3. [Configuration](#configuration) -4. [Rotating mTLS certificates](#rotating-mtls-certificates) -5. [Build and run example](#build-and-run-example) - 1. [Build & Run](#build--run) - 2. [Test with WebClient](#test-with-webclient) - 3. [Test with cURL](#test-with-curl) - -## Prerequisites -- OCI Tenancy with Vault [KMS](https://www.oracle.com/security/cloud-security/key-management) and [Certificate service](https://www.oracle.com/security/cloud-security/ssl-tls-certificates) availability. -- [OCI CLI](https://docs.oracle.com/en-us/iaas/Content/API/SDKDocs/cliinstall.htm#Quickstart) 3.2.1 or later with properly configured `~/.oci/config` to access your tenancy -- OpenSSL (on deb based distros `apt install openssl`) -- [Keytool](https://docs.oracle.com/en/java/javase/17/docs/specs/man/keytool.html) (comes with JDK installation) - -## Setting up OCI - -### Prepare CA(Certification Authority) -Follow [OCI documentation](https://docs.oracle.com/en-us/iaas/Content/certificates/managing-certificate-authorities.htm): -0. Signup or use an OCI tenancy (see above links). -1. Create group `CertificateAuthorityAdmins` and add your user in it. -2. Create dynamic group `CertificateAuthority-DG` with single rule `resource.type='certificateauthority'` -3. Create policy `CertificateAuthority-PL` with following statements: - ``` - Allow dynamic-group CertificateAuthority-DG to use keys in tenancy - Allow dynamic-group CertificateAuthority-DG to manage objects in tenancy - Allow group CertificateAuthorityAdmins to manage certificate-authority-family in tenancy - Allow group CertificateAuthorityAdmins to read keys in tenancy - Allow group CertificateAuthorityAdmins to use key-delegate in tenancy - Allow group CertificateAuthorityAdmins to read buckets in tenancy - Allow group CertificateAuthorityAdmins to read vaults in tenancy - ``` -4. Create policy `Vaults-PL` with following statements: - ``` - Allow group CertificateAuthorityAdmins to manage vaults in tenancy - Allow group CertificateAuthorityAdmins to manage keys in tenancy - Allow group CertificateAuthorityAdmins to manage secret-family in tenancy - ``` -5. Create or reuse an OCI Vault and notice there are cryptographic and management endpoints in the vault general info, we will need them later. -6. Create new key in the vault with following properties: - - Name: `mySuperCAKey` - - Protection Mode: **HSM** (requirement for CA keys, those can't be downloaded) - - Algorithm: **RSA** -7. Create CA: - 1. In OCI menu select `Identity & Security>Certificates>Certificate Authorities` - 2. Select button `Create Certificate Authority` - 3. Choose `Root Certificate Authority` and choose the name, for example `MySuperCA` - 4. Enter CN(Common Name), for example `my.super.authority` - 5. Select your vault and the key `mySuperCAKey` - 6. Select max validity for signed certs(or leave the default 90 days) - 7. Check `Skip Revocation` to keep it simple - 8. Select `Create Certificate Authority` button on the summary page - 9. Notice OCID of the newly created CA, we will need it later - -### Configuration -Following env variables to be configured in [config.sh](etc/unsupported-cert-tools/config.sh) -for both [rotating](#rotating-mtls-certificates) certificates and [running](#build--run) the examples. - -- **COMPARTMENT_OCID** - OCID of compartment the services are in -- **VAULT_CRYPTO_ENDPOINT** - Each OCI Vault has public crypto and management endpoints, we need to specify crypto endpoint of the vault we are rotating the private keys in (example expects both client and server to store private key in the same vault) -- **VAULT_MANAGEMENT_ENDPOINT** - crypto endpoint of the vault we are rotating the private keys in -- **CA_OCID** - OCID of the CA authority we have created in [Prepare CA](#prepare-cacertification-authority) step - -Following env variables are generated automatically by [create-keys.sh](etc/unsupported-cert-tools/create-keys.sh) or needs to be configured manually for [rotate-keys.sh](etc/unsupported-cert-tools/rotate-keys.sh) in [generated-config.sh](etc/unsupported-cert-tools/generated-config.sh) -- **SERVER_CERT_OCID** - OCID of the server certificate(not the specific version!) -- **SERVER_KEY_OCID** - OCID of the server private key in vault(not the specific version!) - -Optional: -- **CLIENT_CERT_OCID** - OCID of the client certificate(not the specific version!) -- **CLIENT_KEY_OCID** - OCID of the client private key in vault(not the specific version!) - -### Prepare keys and certificates -Make sure you are in the directory [./etc/unsupported-cert-tools/](etc/unsupported-cert-tools/). -```shell -cd etc/unsupported-cert-tools/ -bash create-keys.sh -``` - -## Rotating mTLS certificates -Make sure you are in the directory [./etc/unsupported-cert-tools/](etc/unsupported-cert-tools/). -```shell -cd etc/unsupported-cert-tools -bash rotate-keys.sh -``` -⚠️ Keep in mind that rotation creates new [versions](https://docs.oracle.com/en-us/iaas/Content/certificates/rotation-states.htm), OCIDs of the keys and certificates stays the same, and you don't need to change your configuration. - -## Build and run example - -Update the [pom.xml](../pom.xml) to define the system properties for the configuration as mentioned above. - -### Build & Run - -```shell -mvn clean package -``` - -Run mTLS secured web server: -```shell -source ./etc/unsupported-cert-tools/config.sh && \ -source ./etc/unsupported-cert-tools/generated-config.sh && \ -java -jar ./target/helidon-examples-microprofile-oci-tls-certificates.jar -``` - -### Test with cURL -```shell -curl --key key-pair.pem --cert cert-chain.cer --cacert ca.cer -v https://localhost:8443 -``` diff --git a/examples/microprofile/oci-tls-certificates/etc/unsupported-cert-tools/config.sh b/examples/microprofile/oci-tls-certificates/etc/unsupported-cert-tools/config.sh deleted file mode 100644 index 56250e152de..00000000000 --- a/examples/microprofile/oci-tls-certificates/etc/unsupported-cert-tools/config.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -# -# Copyright (c) 2023 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. -# - -# The caller should update these accordingly -export COMPARTMENT_OCID=ocid1.tenancy.oc1.. -export VAULT_CRYPTO_ENDPOINT=https://TODO.oraclecloud.com -export VAULT_MANAGEMENT_ENDPOINT=https://TODO.oraclecloud.com -export CA_OCID=TODO -export DISPLAY_NAME_PREFIX="tls-test-1" diff --git a/examples/microprofile/oci-tls-certificates/etc/unsupported-cert-tools/create-keys.sh b/examples/microprofile/oci-tls-certificates/etc/unsupported-cert-tools/create-keys.sh deleted file mode 100644 index 49ba4e63c84..00000000000 --- a/examples/microprofile/oci-tls-certificates/etc/unsupported-cert-tools/create-keys.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash - -# -# Copyright (c) 2023, 2024 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. -# - -set -e - -# shellcheck disable=SC1091 -source ./config.sh -# shellcheck disable=SC1091 -source ./utils.sh - -# Cleanup -rm -rf ./server ./client -mkdir -p server client - -CDIR=$(pwd) - -# Rotate server cert and key -cd "${CDIR}/server" -genCertAndCSR server -NEW_SERVER_CERT_OCID=$(uploadNewCert server "${DISPLAY_NAME_PREFIX}") -prepareKeyToUpload server -# shellcheck disable=SC2086 -NEW_SERVER_KEY_OCID=$(createKeyInVault server ${DISPLAY_NAME_PREFIX}) - -# Rotate client cert and key -cd "${CDIR}/client" -genCertAndCSR client -NEW_CLIENT_CERT_OCID=$(uploadNewCert client "${DISPLAY_NAME_PREFIX}") -prepareKeyToUpload client -NEW_CLIENT_KEY_OCID=$(createKeyInVault client "${DISPLAY_NAME_PREFIX}") - -echo "======= ALL done! =======" -echo "Newly created OCI resources:" -echo "Server certificate OCID: ${NEW_SERVER_CERT_OCID}" -echo "Server private key OCID: ${NEW_SERVER_KEY_OCID}" -echo "Client certificate OCID: ${NEW_CLIENT_CERT_OCID}" -echo "Client private key OCID: ${NEW_CLIENT_KEY_OCID}" -echo "Saving to gen-config.sh" -tee "${CDIR}/generated-config.sh" << EOF -#!/bin/bash -## Content of this file gets rewritten by create-keys.sh -export SERVER_CERT_OCID=${NEW_SERVER_CERT_OCID} -export SERVER_KEY_OCID=${NEW_SERVER_KEY_OCID} - -export CLIENT_CERT_OCID=${NEW_CLIENT_CERT_OCID} -export CLIENT_KEY_OCID=${NEW_CLIENT_KEY_OCID} -EOF diff --git a/examples/microprofile/oci-tls-certificates/etc/unsupported-cert-tools/generated-config.sh b/examples/microprofile/oci-tls-certificates/etc/unsupported-cert-tools/generated-config.sh deleted file mode 100644 index 36dd98e6654..00000000000 --- a/examples/microprofile/oci-tls-certificates/etc/unsupported-cert-tools/generated-config.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -# -# Copyright (c) 2023 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. -# - -## Content of this file gets rewritten by create-keys.sh -export SERVER_CERT_OCID=ocid1.certificate.oc1. -export SERVER_KEY_OCID=ocid1.key.oc1. - -export CLIENT_CERT_OCID=ocid1.certificate.oc1. -export CLIENT_KEY_OCID=ocid1.key.oc1. diff --git a/examples/microprofile/oci-tls-certificates/etc/unsupported-cert-tools/rotate-keys.sh b/examples/microprofile/oci-tls-certificates/etc/unsupported-cert-tools/rotate-keys.sh deleted file mode 100644 index e709c9db331..00000000000 --- a/examples/microprofile/oci-tls-certificates/etc/unsupported-cert-tools/rotate-keys.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash - -# -# Copyright (c) 2023, 2024 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. -# - -set -e - -# shellcheck disable=SC1091 -source ./config.sh -# shellcheck disable=SC1091 -source ./generated-config.sh -# shellcheck disable=SC1091 -source ./utils.sh - -# Cleanup -rm -rf ./server ./client -mkdir -p server client - -CDIR=$(pwd) - -# Rotate server cert and key -cd "${CDIR}/server" -genCertAndCSR server -rotateCert server "${SERVER_CERT_OCID}" -prepareKeyToUpload server -rotateKeyInVault server "${SERVER_KEY_OCID}" - -# Rotate client cert and key -cd "${CDIR}/client" -genCertAndCSR client -rotateCert client "${CLIENT_CERT_OCID}" -prepareKeyToUpload client -# shellcheck disable=SC2086 -rotateKeyInVault client ${CLIENT_KEY_OCID} - -echo "ALL done!" diff --git a/examples/microprofile/oci-tls-certificates/etc/unsupported-cert-tools/utils.sh b/examples/microprofile/oci-tls-certificates/etc/unsupported-cert-tools/utils.sh deleted file mode 100644 index 8955c80ee40..00000000000 --- a/examples/microprofile/oci-tls-certificates/etc/unsupported-cert-tools/utils.sh +++ /dev/null @@ -1,161 +0,0 @@ -#!/bin/bash -e - -# -# Copyright (c) 2023, 2024 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. -# - -set -e - -PRIVATE_KEY_AS_PEM=private-key.pem -VAULT_PUBLIC_WRAPPING_KEY_PATH=vaultWrappingPub.key -PRIVATE_KEY_AS_DER=uploadedKey.der -TEMPORARY_AES_KEY_PATH=tmpAES.key -WRAPPED_TEMPORARY_AES_KEY_FILE=wrappedTmpAES.key -WRAPPED_TARGET_KEY_FILE=wrappedUploadedKey.key -WRAPPED_KEY_MATERIAL_FILE=readyToUpload.der - -prepareKeyToUpload() { - KEYSTORE_FILE=${1}.jks - - # Obtain OCI wrapping key - oci kms management wrapping-key get \ - --query 'data."public-key"' \ - --raw-output \ - --endpoint "${VAULT_MANAGEMENT_ENDPOINT}" \ - > ${VAULT_PUBLIC_WRAPPING_KEY_PATH} - - # Extract server/client private key - openssl pkcs12 -in "${KEYSTORE_FILE}" \ - -nocerts \ - -passin pass:changeit -passout pass:changeit \ - -out $PRIVATE_KEY_AS_PEM - - ## Upload server/client private key to vault - # Generate a temporary AES key - openssl rand -out ${TEMPORARY_AES_KEY_PATH} 32 - - # Wrap the temporary AES key with the public wrapping key using RSA-OAEP with SHA-256: - openssl pkeyutl -encrypt -in $TEMPORARY_AES_KEY_PATH \ - -inkey $VAULT_PUBLIC_WRAPPING_KEY_PATH \ - -pubin -out $WRAPPED_TEMPORARY_AES_KEY_FILE \ - -pkeyopt rsa_padding_mode:oaep \ - -pkeyopt rsa_oaep_md:sha256 - - # Generate hexadecimal of the temporary AES key material: - TEMPORARY_AES_KEY_HEXDUMP=$(hexdump -v -e '/1 "%02x"' <${TEMPORARY_AES_KEY_PATH}) - - # If the RSA private key you want to import is in PEM format, convert it to DER: - openssl pkcs8 -topk8 -nocrypt \ - -inform PEM -outform DER \ - -passin pass:changeit -passout pass:changeit \ - -in ${PRIVATE_KEY_AS_PEM} -out ${PRIVATE_KEY_AS_DER} - - # Wrap RSA private key with the temporary AES key: - openssl enc -id-aes256-wrap-pad -iv A65959A6 -K "${TEMPORARY_AES_KEY_HEXDUMP}" -in ${PRIVATE_KEY_AS_DER} -out ${WRAPPED_TARGET_KEY_FILE} - - # Create the wrapped key material by concatenating both wrapped keys: - cat ${WRAPPED_TEMPORARY_AES_KEY_FILE} ${WRAPPED_TARGET_KEY_FILE} >${WRAPPED_KEY_MATERIAL_FILE} - -# linux -# KEY_MATERIAL_AS_BASE64=$(base64 -w 0 readyToUpload.der) -# macOS - KEY_MATERIAL_AS_BASE64=$(base64 -i readyToUpload.der) - - JSON_KEY_MATERIAL="{\"keyMaterial\": \"${KEY_MATERIAL_AS_BASE64}\",\"wrappingAlgorithm\": \"RSA_OAEP_AES_SHA256\"}" - - echo "${JSON_KEY_MATERIAL}" >key-material.json -} - -createKeyInVault() { - TYPE=${1} - KEY_NAME=${2} - - NEW_KEY_OCID=$(oci kms management key import \ - --compartment-id "${COMPARTMENT_OCID}" \ - --display-name "${KEY_NAME}-${TYPE}" \ - --key-shape '{"algorithm": "RSA", "length": 256}' \ - --protection-mode SOFTWARE \ - --endpoint "${VAULT_MANAGEMENT_ENDPOINT}" \ - --wrapped-import-key file://key-material.json \ - --query 'data.id' \ - --raw-output) - export NEW_KEY_OCID - - echo "${NEW_KEY_OCID}" -} - -rotateKeyInVault() { - TYPE=${1} - KEY_OCID=${2} - - oci kms management key-version import \ - --key-id "${KEY_OCID}" \ - --endpoint "${VAULT_MANAGEMENT_ENDPOINT}" \ - --wrapped-import-key file://key-material.json -} - -genCertAndCSR() { - TYPE=${1} - - # Get CA cert - oci certificates certificate-authority-bundle get --query 'data."certificate-pem"' \ - --raw-output \ - --certificate-authority-id "${CA_OCID}" \ - > ca.pem - - # Generating new server key store - keytool -genkeypair -keyalg RSA -keysize 2048 \ - -alias "${TYPE}" \ - -dname "CN=localhost" \ - -validity 60 \ - -keystore "${TYPE}.jks" \ - -storepass password -keypass password \ - -deststoretype pkcs12 - - # Create CSR - keytool -certreq -keystore "${TYPE}.jks" \ - -alias "${TYPE}" \ - -keypass password \ - -storepass password \ - -validity 60 \ - -keyalg rsa \ - -file "${TYPE}.csr" -} - -uploadNewCert() { - TYPE=${1} - CERT_NAME=${2} - ## Create server/client certificate in OCI - NEW_CERT_OCID=$(oci certs-mgmt certificate create-certificate-managed-externally-issued-by-internal-ca \ - --compartment-id "${COMPARTMENT_OCID}" \ - --issuer-certificate-authority-id "${CA_OCID}" \ - --name "${CERT_NAME}-${TYPE}" \ - --csr-pem "$(cat "${TYPE}.csr")" \ - --query 'data.id' \ - --raw-output) - export NEW_CERT_OCID - - echo "${NEW_CERT_OCID}" -} - -rotateCert() { - TYPE=${1} - CERT_OCID=${2} - - ## Renew server certificate in OCI - oci certs-mgmt certificate update-certificate-managed-externally \ - --certificate-id "${CERT_OCID}" \ - --csr-pem "$(cat "${TYPE}.csr")" -} diff --git a/examples/microprofile/oci-tls-certificates/pom.xml b/examples/microprofile/oci-tls-certificates/pom.xml deleted file mode 100644 index 4f99f82a0bb..00000000000 --- a/examples/microprofile/oci-tls-certificates/pom.xml +++ /dev/null @@ -1,108 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../applications/mp/pom.xml - - - io.helidon.examples.microprofile - helidon-examples-microprofile-oci-tls-certificates - Helidon Microprofile Examples TLS Manager and OCI Certificates Service Integration - - - Microprofile example that configures TLS via a Manager and OCI Certificates Service integration with cert rotation - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.integrations.oci - helidon-integrations-oci-tls-certificates - - - io.smallrye - jandex - runtime - true - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - com.oracle.oci.sdk - oci-java-sdk-common-httpclient-jersey3 - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - maven-surefire-plugin - - - - - - - - - ${project.build.testOutputDirectory}/logging.properties - jdk - - - - - - - diff --git a/examples/microprofile/oci-tls-certificates/src/main/java/io/helidon/examples/microprofile/oci/tls/certificates/GreetResource.java b/examples/microprofile/oci-tls-certificates/src/main/java/io/helidon/examples/microprofile/oci/tls/certificates/GreetResource.java deleted file mode 100644 index 7018a15a04d..00000000000 --- a/examples/microprofile/oci-tls-certificates/src/main/java/io/helidon/examples/microprofile/oci/tls/certificates/GreetResource.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2023 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.microprofile.oci.tls.certificates; - -import jakarta.enterprise.context.RequestScoped; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; - -/** - * A simple JAX-RS resource to greet you. - */ -@Path("/") -@RequestScoped -public class GreetResource { - - /** - * Return a greeting message. - * - * @return greeting - */ - @GET - @Produces(MediaType.TEXT_PLAIN) - public String getDefaultMessage() { - return "Hello user!"; - } - -} diff --git a/examples/microprofile/oci-tls-certificates/src/main/java/io/helidon/examples/microprofile/oci/tls/certificates/Main.java b/examples/microprofile/oci-tls-certificates/src/main/java/io/helidon/examples/microprofile/oci/tls/certificates/Main.java deleted file mode 100644 index 7dbab261273..00000000000 --- a/examples/microprofile/oci-tls-certificates/src/main/java/io/helidon/examples/microprofile/oci/tls/certificates/Main.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2023 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.microprofile.oci.tls.certificates; - -import io.helidon.microprofile.server.Server; - -/** - * Starts the server. - */ -public final class Main { - - private Main() { - } - - /** - * Main method. - * - * @param args args - */ - public static void main(final String[] args) { - startServer(); - } - - static Server startServer() { - return Server.create().start(); - } - -} diff --git a/examples/microprofile/oci-tls-certificates/src/main/java/io/helidon/examples/microprofile/oci/tls/certificates/package-info.java b/examples/microprofile/oci-tls-certificates/src/main/java/io/helidon/examples/microprofile/oci/tls/certificates/package-info.java deleted file mode 100644 index 462af104dd7..00000000000 --- a/examples/microprofile/oci-tls-certificates/src/main/java/io/helidon/examples/microprofile/oci/tls/certificates/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2023 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. - */ - -/** - * Helidon Microprofile Examples OCI TLS Manager. - */ -package io.helidon.examples.microprofile.oci.tls.certificates; diff --git a/examples/microprofile/oci-tls-certificates/src/main/resources/META-INF/beans.xml b/examples/microprofile/oci-tls-certificates/src/main/resources/META-INF/beans.xml deleted file mode 100644 index cf179d28185..00000000000 --- a/examples/microprofile/oci-tls-certificates/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/microprofile/oci-tls-certificates/src/main/resources/application.yaml b/examples/microprofile/oci-tls-certificates/src/main/resources/application.yaml deleted file mode 100644 index f2443749791..00000000000 --- a/examples/microprofile/oci-tls-certificates/src/main/resources/application.yaml +++ /dev/null @@ -1,37 +0,0 @@ -# -# Copyright (c) 2023 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 - sockets: - - name: "secured" - port: 8443 - tls: - # for server-side auth this should be set to false (or removed altogether) - trust-all: true - manager: - oci-certificates-tls-manager: - # Download mTls context every 30 seconds - schedule: "0/30 * * * * ? *" - # Each OCI Vault has public crypto and management endpoints - vault-crypto-endpoint: ${VAULT_CRYPTO_ENDPOINT} - # Certification Authority in OCI we have signed rotated certificates with - ca-ocid: ${CA_OCID} - cert-ocid: ${SERVER_CERT_OCID} - key-ocid: ${SERVER_KEY_OCID} - # note that this will eventually come from the OCI Vault Config Source - https://github.com/helidon-io/helidon/issues/4238 - key-password: password diff --git a/examples/microprofile/oci-tls-certificates/src/main/resources/logging.properties b/examples/microprofile/oci-tls-certificates/src/main/resources/logging.properties deleted file mode 100644 index 5dbc87c3d29..00000000000 --- a/examples/microprofile/oci-tls-certificates/src/main/resources/logging.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright (c) 2023 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. -# - -# 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=%5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO - -io.helidon.level=INFO -io.helidon.integrations.level=INFO - -# OCI SDK logging -com.oracle.bmc.level=WARNING diff --git a/examples/microprofile/oci-tls-certificates/src/main/resources/oci.yaml b/examples/microprofile/oci-tls-certificates/src/main/resources/oci.yaml deleted file mode 100644 index 9f2ca2ef77b..00000000000 --- a/examples/microprofile/oci-tls-certificates/src/main/resources/oci.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2023 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. -# - -auth-strategies: ["instance-principals", "config-file", "resource-principal", "config"] diff --git a/examples/microprofile/oci-tls-certificates/src/test/java/io/helidon/examples/microprofile/oci/tls/certificates/SimpleUsageTest.java b/examples/microprofile/oci-tls-certificates/src/test/java/io/helidon/examples/microprofile/oci/tls/certificates/SimpleUsageTest.java deleted file mode 100644 index 5d5ad51fe7c..00000000000 --- a/examples/microprofile/oci-tls-certificates/src/test/java/io/helidon/examples/microprofile/oci/tls/certificates/SimpleUsageTest.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2023 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.microprofile.oci.tls.certificates; - -import java.net.URI; -import java.security.cert.X509Certificate; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; - -import io.helidon.microprofile.server.Server; - -import jakarta.ws.rs.client.Client; -import jakarta.ws.rs.client.ClientBuilder; -import jakarta.ws.rs.core.Response; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assumptions.assumeTrue; - -/** - * Start the server that will download and watch OCI's Certificates service for dynamic updates. - */ -class SimpleUsageTest { - - private static Client client; - static { - try { - SSLContext sslcontext = SSLContext.getInstance("TLS"); - sslcontext.init(null, new TrustManager[]{new X509TrustManager() { - public void checkClientTrusted(X509Certificate[] arg0, String arg1) {} - public void checkServerTrusted(X509Certificate[] arg0, String arg1) {} - public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } - }}, new java.security.SecureRandom()); - - client = ClientBuilder.newBuilder() - .sslContext(sslcontext) - .build(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - @Test - // see pom.xml - public void testIt() { - assumeTrue(System.getProperty("VAULT_CRYPTO_ENDPOINT") != null, - "be sure to set required system properties"); - assumeTrue(System.getProperty("CA_OCID") != null, - "be sure to set required system properties"); - assumeTrue(System.getProperty("SERVER_CERT_OCID") != null, - "be sure to set required system properties"); - assumeTrue(System.getProperty("SERVER_KEY_OCID") != null, - "be sure to set required system properties"); - - Server server = Main.startServer(); - try { - URI restUri = URI.create("https://localhost:" + server.port() + "/"); - try (Response res = client.target(restUri).request().get()) { - assertThat(res.getStatus(), is(200)); - assertThat(res.readEntity(String.class), is("Hello user!")); - } - } finally { - server.stop(); - } - } - -} diff --git a/examples/microprofile/oidc/README.md b/examples/microprofile/oidc/README.md deleted file mode 100644 index 81ff0e7a78d..00000000000 --- a/examples/microprofile/oidc/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# Security integration with OIDC - -This example demonstrates integration with OIDC (Open ID Connect) providers. - -## Contents - -MP example that integrates with an OIDC provider. - -To configure this example, you need to replace the following: -1. src/main/resources/application.yaml - set security.properties.oidc-* to your tenant and application configuration - -## Running the Example - -Run the "OidcMain" class for file configuration based example. - -## Local configuration - -The example is already set up to read -`${user.home}/helidon/conf/examples.yaml` to override defaults configured -in `application.yaml`. - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-microprofile-security-oidc-login.jar -``` diff --git a/examples/microprofile/oidc/pom.xml b/examples/microprofile/oidc/pom.xml deleted file mode 100644 index 13094c3ea71..00000000000 --- a/examples/microprofile/oidc/pom.xml +++ /dev/null @@ -1,80 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.microprofile - helidon-examples-microprofile-security-oidc-login - Helidon Examples Microprofile OIDC Security - - - Microprofile example with (any) OIDC provider integration. - - - - io.helidon.examples.microprofile.security.oidc.OidcMain - - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.microprofile - helidon-microprofile-oidc - - - io.smallrye - jandex - runtime - true - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/microprofile/oidc/src/main/java/io/helidon/examples/microprofile/security/oidc/OidcMain.java b/examples/microprofile/oidc/src/main/java/io/helidon/examples/microprofile/security/oidc/OidcMain.java deleted file mode 100644 index bef6c09ae09..00000000000 --- a/examples/microprofile/oidc/src/main/java/io/helidon/examples/microprofile/security/oidc/OidcMain.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2019, 2021 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.microprofile.security.oidc; - -import io.helidon.config.Config; -import io.helidon.microprofile.server.Server; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.file; - -/** - * Main class for MP. - */ -public final class OidcMain { - private OidcMain() { - } - - /** - * Start the application. - * @param args ignored. - */ - public static void main(String[] args) { - Server server = Server.builder() - .config(buildConfig()) - .build() - .start(); - - System.out.println("http://localhost:" + server.port() + "/test"); - } - - private static Config buildConfig() { - return Config.builder() - .sources( - // you can use this file to override the defaults that are built-in - file(System.getProperty("user.home") + "/helidon/conf/examples.yaml").optional(), - // in jar file (see src/main/resources/application.yaml) - classpath("application.yaml")) - .build(); - } -} diff --git a/examples/microprofile/oidc/src/main/java/io/helidon/examples/microprofile/security/oidc/OidcResource.java b/examples/microprofile/oidc/src/main/java/io/helidon/examples/microprofile/security/oidc/OidcResource.java deleted file mode 100644 index c8b28ad36bd..00000000000 --- a/examples/microprofile/oidc/src/main/java/io/helidon/examples/microprofile/security/oidc/OidcResource.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2019, 2021 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.microprofile.security.oidc; - -import io.helidon.security.SecurityContext; -import io.helidon.security.annotations.Authenticated; - -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.core.Context; - -/** - * A simple JAX-RS resource with a single GET method. - */ -@Path("/test") -public class OidcResource { - - /** - * Hello world using security context. - * @param securityContext context as established during login - * @return a string with current username - */ - @Authenticated - @GET - public String getIt(@Context SecurityContext securityContext) { - return "Hello " + securityContext.userName(); - } - -} diff --git a/examples/microprofile/oidc/src/main/java/io/helidon/examples/microprofile/security/oidc/package-info.java b/examples/microprofile/oidc/src/main/java/io/helidon/examples/microprofile/security/oidc/package-info.java deleted file mode 100644 index 598a0f5f907..00000000000 --- a/examples/microprofile/oidc/src/main/java/io/helidon/examples/microprofile/security/oidc/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2019, 2021 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. - */ -/** - * An OIDC (Open ID Connect) example. - */ -package io.helidon.examples.microprofile.security.oidc; diff --git a/examples/microprofile/oidc/src/main/resources/META-INF/beans.xml b/examples/microprofile/oidc/src/main/resources/META-INF/beans.xml deleted file mode 100644 index a234c147019..00000000000 --- a/examples/microprofile/oidc/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - diff --git a/examples/microprofile/oidc/src/main/resources/application.yaml b/examples/microprofile/oidc/src/main/resources/application.yaml deleted file mode 100644 index c3def999ac2..00000000000 --- a/examples/microprofile/oidc/src/main/resources/application.yaml +++ /dev/null @@ -1,54 +0,0 @@ -# -# Copyright (c) 2019, 2024 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: 7987 -security: - config.require-encryption: false - properties: - # this should be defined by the identity server - oidc-identity-uri: "https://tenant.some-server.com/oauth2/default" - # when you create a new client in identity server configuration, you should get a client id and a client secret - oidc-client-id: "some client id" - oidc-client-secret: "changeit" - # issuer of the tokens - identity server specific (maybe even configurable) - oidc-issuer: "https://tenant.some-server.com/oauth2/default" - # audience of the tokens - identity server specific (usually configurable) - oidc-audience: "configured audience" - # The frontend URI defines the possible load balancer address - # The redirect URI used is ${frontend-uri}${redirect-uri} - # Webserver is by default listening on /oidc/redirect - this can be modified by `redirect-uri` option in oidc configuration - frontend-uri: "http://localhost:7987" - server-type: "@default" - providers: - - abac: - # Adds ABAC Provider - it does not require any configuration - - oidc: - # use a custom name, so it does not clash with other examples - cookie-name: "OIDC_EXAMPLE_COOKIE" - # support for "Authorization" header with bearer token - header-use: true - # the default redirect-uri, where the webserver listens on redirects from identity server - redirect-uri: "/oidc/redirect" - issuer: "${security.properties.oidc-issuer}" - audience: "${security.properties.oidc-audience}" - client-id: "${security.properties.oidc-client-id}" - client-secret: "${security.properties.oidc-client-secret}" - identity-uri: "${security.properties.oidc-identity-uri}" - frontend-uri: "${security.properties.frontend-uri}" - server-type: "${security.properties.server-type}" - # We want to redirect to login page (and token can be received either through cookie or header) - redirect: true \ No newline at end of file diff --git a/examples/microprofile/oidc/src/main/resources/logging.properties b/examples/microprofile/oidc/src/main/resources/logging.properties deleted file mode 100644 index a0f8cb75957..00000000000 --- a/examples/microprofile/oidc/src/main/resources/logging.properties +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2019, 2020 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. -# - -handlers = java.util.logging.ConsoleHandler - -java.util.logging.ConsoleHandler.level = FINEST -java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter -java.util.logging.SimpleFormatter.format = [%1$tc] %4$s: %2$s - %5$s %6$s%n - -.level = INFO -io.helidon.config.level = WARNING -# io.helidon.security.providers.oidc.level = FINEST -AUDIT.level=FINEST -# to see detailed information about failed validations of tokens -io.helidon.security.providers.oidc.level=FINEST diff --git a/examples/microprofile/openapi/README.md b/examples/microprofile/openapi/README.md deleted file mode 100644 index 3141be919f2..00000000000 --- a/examples/microprofile/openapi/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# Helidon MP OpenAPI Example - -This example shows a simple greeting application, similar to the one from the -Helidon MP QuickStart, enhanced with OpenAPI support. - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-microprofile-openapi.jar -``` - -Try the endpoints: - -```shell -curl -X GET http://localhost:8080/greet -#Output: {"message":"Hello World!"} - -curl -X GET http://localhost:8080/greet/Joe -#Output: {"message":"Hello Joe!"} - -curl -X PUT -H "Content-Type: application/json" -d '{"message" : "Hola"}' http://localhost:8080/greet/greeting - -curl -X GET http://localhost:8080/greet/Jose -#Output: {"message":"Hola Jose!"} - -curl -X GET http://localhost:8080/openapi -#Output: [lengthy OpenAPI document] -``` -The output describes not only then endpoints from `GreetResource` but -also one contributed by the `SimpleAPIModelReader`. - - diff --git a/examples/microprofile/openapi/pom.xml b/examples/microprofile/openapi/pom.xml deleted file mode 100644 index 14cb9754b24..00000000000 --- a/examples/microprofile/openapi/pom.xml +++ /dev/null @@ -1,98 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.microprofile - helidon-examples-microprofile-openapi - Helidon Examples Microprofile OpenAPI - - - - io.helidon.microprofile.bundles - helidon-microprofile-core - - - io.helidon.microprofile.openapi - helidon-microprofile-openapi - - - io.helidon.logging - helidon-logging-jul - runtime - - - org.glassfish.jersey.media - jersey-media-json-binding - runtime - - - io.smallrye - jandex - runtime - true - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.microprofile.testing - helidon-microprofile-testing-junit5 - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/microprofile/openapi/src/main/java/io/helidon/microprofile/examples/openapi/GreetResource.java b/examples/microprofile/openapi/src/main/java/io/helidon/microprofile/examples/openapi/GreetResource.java deleted file mode 100644 index fb9d82629a5..00000000000 --- a/examples/microprofile/openapi/src/main/java/io/helidon/microprofile/examples/openapi/GreetResource.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.microprofile.examples.openapi; - -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.Operation; -import org.eclipse.microprofile.openapi.annotations.media.Content; -import org.eclipse.microprofile.openapi.annotations.media.ExampleObject; -import org.eclipse.microprofile.openapi.annotations.media.Schema; -import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody; -import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; - -/** - * A simple JAX-RS resource with OpenAPI annotations 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 - * - * Get OpenAPI document for the endpoints - * curl -X GET http://localhost:8080/openapi - * - * Note that the output will include not only the annotated endpoints from this - * class but also an endpoint added by the - * {@link io.helidon.microprofile.examples.openapi.internal.SimpleAPIModelReader}. - * - * 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 GreetingMessage} - */ - @GET - @Operation(summary = "Returns a generic greeting", - description = "Greets the user generically") - @APIResponse(description = "Simple JSON containing the greeting", - content = @Content(mediaType = "application/json", - schema = @Schema(implementation = GreetingMessage.class))) - @Produces(MediaType.APPLICATION_JSON) - public GreetingMessage getDefaultMessage() { - return createResponse("World"); - } - - /** - * Return a greeting message using the name that was provided. - * - * @param name the name to greet - * @return {@link GreetingMessage} - */ - @Path("/{name}") - @GET - @Operation(summary = "Returns a personalized greeting") - @APIResponse(description = "Simple JSON containing the greeting", - content = @Content(mediaType = "application/json", - schema = @Schema(implementation = GreetingMessage.class))) - @Produces(MediaType.APPLICATION_JSON) - public GreetingMessage getMessage(@PathParam("name") String name) { - return createResponse(name); - } - - /** - * Set the greeting to use in future messages. - * - * @param message JSON containing the new greeting - * @return {@link Response} - */ - @Path("/greeting") - @PUT - @Operation(summary = "Set the greeting prefix", - description = "Permits the client to set the prefix part of the greeting (\"Hello\")") - @RequestBody( - name = "greeting", - description = "Conveys the new greeting prefix to use in building greetings", - content = @Content( - mediaType = "application/json", - schema = @Schema(implementation = GreetingMessage.class), - examples = @ExampleObject( - name = "greeting", - summary = "Example greeting message to update", - value = "{\"greeting\": \"New greeting message\"}"))) - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - public Response updateGreeting(GreetingMessage message) { - if (message.getMessage() == null) { - GreetingMessage entity = new GreetingMessage("No greeting provided"); - return Response.status(Response.Status.BAD_REQUEST).entity(entity).build(); - } - - greetingProvider.setMessage(message.getMessage()); - return Response.status(Response.Status.NO_CONTENT).build(); - } - - private GreetingMessage createResponse(String who) { - String msg = String.format("%s %s!", greetingProvider.getMessage(), who); - - return new GreetingMessage(msg); - } -} diff --git a/examples/microprofile/openapi/src/main/java/io/helidon/microprofile/examples/openapi/GreetingMessage.java b/examples/microprofile/openapi/src/main/java/io/helidon/microprofile/examples/openapi/GreetingMessage.java deleted file mode 100644 index 84d9e9e98c0..00000000000 --- a/examples/microprofile/openapi/src/main/java/io/helidon/microprofile/examples/openapi/GreetingMessage.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2023 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.microprofile.examples.openapi; - -/** - * POJO defining the greeting message content. - */ -@SuppressWarnings("unused") -public class GreetingMessage { - private String message; - - /** - * Create a new GreetingMessage instance. - */ - public GreetingMessage() { - } - - /** - * Create a new GreetingMessage instance. - * - * @param message message - */ - public GreetingMessage(String message) { - this.message = message; - } - - /** - * Gets the message value. - * - * @return message value - */ - public String getMessage() { - return message; - } - - /** - * Sets the message value. - * - * @param message message value to set - */ - public void setMessage(String message) { - this.message = message; - } -} diff --git a/examples/microprofile/openapi/src/main/java/io/helidon/microprofile/examples/openapi/GreetingProvider.java b/examples/microprofile/openapi/src/main/java/io/helidon/microprofile/examples/openapi/GreetingProvider.java deleted file mode 100644 index de2f56e1e88..00000000000 --- a/examples/microprofile/openapi/src/main/java/io/helidon/microprofile/examples/openapi/GreetingProvider.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.microprofile.examples.openapi; - -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/openapi/src/main/java/io/helidon/microprofile/examples/openapi/internal/SimpleAPIFilter.java b/examples/microprofile/openapi/src/main/java/io/helidon/microprofile/examples/openapi/internal/SimpleAPIFilter.java deleted file mode 100644 index 8b68da5c7cd..00000000000 --- a/examples/microprofile/openapi/src/main/java/io/helidon/microprofile/examples/openapi/internal/SimpleAPIFilter.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.microprofile.examples.openapi.internal; - -import java.util.Map; - -import org.eclipse.microprofile.openapi.OASFilter; -import org.eclipse.microprofile.openapi.models.Operation; -import org.eclipse.microprofile.openapi.models.PathItem; - -/** - * Example OpenAPI filter which hides a single endpoint from the OpenAPI document. - */ -public class SimpleAPIFilter implements OASFilter { - - @Override - public PathItem filterPathItem(PathItem pathItem) { - for (Map.Entry methodOp - : pathItem.getOperations().entrySet()) { - if (SimpleAPIModelReader.DOOMED_OPERATION_ID - .equals(methodOp.getValue().getOperationId())) { - return null; - } - } - return OASFilter.super.filterPathItem(pathItem); - } -} diff --git a/examples/microprofile/openapi/src/main/java/io/helidon/microprofile/examples/openapi/internal/SimpleAPIModelReader.java b/examples/microprofile/openapi/src/main/java/io/helidon/microprofile/examples/openapi/internal/SimpleAPIModelReader.java deleted file mode 100644 index b88717f377a..00000000000 --- a/examples/microprofile/openapi/src/main/java/io/helidon/microprofile/examples/openapi/internal/SimpleAPIModelReader.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.microprofile.examples.openapi.internal; - -import org.eclipse.microprofile.openapi.OASFactory; -import org.eclipse.microprofile.openapi.OASModelReader; -import org.eclipse.microprofile.openapi.models.OpenAPI; -import org.eclipse.microprofile.openapi.models.PathItem; -import org.eclipse.microprofile.openapi.models.Paths; - -/** - * Defines two paths using the OpenAPI model reader mechanism, one that should - * be suppressed by the filter class and one that should appear in the published - * OpenAPI document. - */ -public class SimpleAPIModelReader implements OASModelReader { - - /** - * Path for the example endpoint added by this model reader that should be visible. - */ - public static final String MODEL_READER_PATH = "/test/newpath"; - - /** - * Path for an endpoint that the filter should hide. - */ - public static final String DOOMED_PATH = "/test/doomed"; - - /** - * ID for an endpoint that the filter should hide. - */ - public static final String DOOMED_OPERATION_ID = "doomedPath"; - - /** - * Summary text for the endpoint. - */ - public static final String SUMMARY = "A sample test endpoint from ModelReader"; - - @Override - public OpenAPI buildModel() { - /* - * Add two path items, one of which we expect to be removed by - * the filter and a very simple one that will appear in the - * published OpenAPI document. - */ - PathItem newPathItem = OASFactory.createPathItem() - .GET(OASFactory.createOperation() - .operationId("newPath") - .summary(SUMMARY)); - PathItem doomedPathItem = OASFactory.createPathItem() - .GET(OASFactory.createOperation() - .operationId(DOOMED_OPERATION_ID) - .summary("This should become invisible")); - OpenAPI openAPI = OASFactory.createOpenAPI(); - Paths paths = OASFactory.createPaths() - .addPathItem(MODEL_READER_PATH, newPathItem) - .addPathItem(DOOMED_PATH, doomedPathItem); - openAPI.paths(paths); - - return openAPI; - } -} diff --git a/examples/microprofile/openapi/src/main/java/io/helidon/microprofile/examples/openapi/internal/package-info.java b/examples/microprofile/openapi/src/main/java/io/helidon/microprofile/examples/openapi/internal/package-info.java deleted file mode 100644 index 76e52456f8a..00000000000 --- a/examples/microprofile/openapi/src/main/java/io/helidon/microprofile/examples/openapi/internal/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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. - */ - -/** - * Internal classes supporting Helidon MP OpenAPI. - */ -package io.helidon.microprofile.examples.openapi.internal; diff --git a/examples/microprofile/openapi/src/main/java/io/helidon/microprofile/examples/openapi/package-info.java b/examples/microprofile/openapi/src/main/java/io/helidon/microprofile/examples/openapi/package-info.java deleted file mode 100644 index db5a831b38d..00000000000 --- a/examples/microprofile/openapi/src/main/java/io/helidon/microprofile/examples/openapi/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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. - */ - -/** - * Helidon MicroProfile OpenAPI example. - */ -package io.helidon.microprofile.examples.openapi; diff --git a/examples/microprofile/openapi/src/main/resources/META-INF/beans.xml b/examples/microprofile/openapi/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 7785b13b791..00000000000 --- a/examples/microprofile/openapi/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/microprofile/openapi/src/main/resources/META-INF/microprofile-config.properties b/examples/microprofile/openapi/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index af475566e04..00000000000 --- a/examples/microprofile/openapi/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2019, 2023 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. -# - -# Application properties. This is the default greeting -app.greeting=Hello - -# Microprofile server properties -server.port=8080 -server.host=0.0.0.0 - -mp.openapi.filter=io.helidon.microprofile.examples.openapi.internal.SimpleAPIFilter -mp.openapi.model.reader=io.helidon.microprofile.examples.openapi.internal.SimpleAPIModelReader diff --git a/examples/microprofile/openapi/src/main/resources/logging.properties b/examples/microprofile/openapi/src/main/resources/logging.properties deleted file mode 100644 index 9369785375b..00000000000 --- a/examples/microprofile/openapi/src/main/resources/logging.properties +++ /dev/null @@ -1,36 +0,0 @@ -# -# Copyright (c) 2019, 2024 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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.microprofile.level=INFO -#io.helidon.common.level=INFO -#org.glassfish.jersey.level=INFO -#org.jboss.weld=INFO diff --git a/examples/microprofile/openapi/src/test/java/io/helidon/microprofile/examples/openapi/MainTest.java b/examples/microprofile/openapi/src/test/java/io/helidon/microprofile/examples/openapi/MainTest.java deleted file mode 100644 index 65d31e9f4ba..00000000000 --- a/examples/microprofile/openapi/src/test/java/io/helidon/microprofile/examples/openapi/MainTest.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.microprofile.examples.openapi; - -import io.helidon.microprofile.examples.openapi.internal.SimpleAPIModelReader; -import io.helidon.microprofile.testing.junit5.HelidonTest; - -import jakarta.inject.Inject; -import jakarta.json.Json; -import jakarta.json.JsonObject; -import jakarta.json.JsonPointer; -import jakarta.json.JsonString; -import jakarta.ws.rs.client.Entity; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -@HelidonTest -class MainTest { - - private final WebTarget target; - - @Inject - MainTest(WebTarget target) { - this.target = target; - } - - @Test - void testHelloWorld() { - GreetingMessage message = target.path("/greet") - .request() - .get(GreetingMessage.class); - assertThat("default message", message.getMessage(), - is("Hello World!")); - - message = target.path("/greet/Joe") - .request() - .get(GreetingMessage.class); - assertThat("hello Joe message", message.getMessage(), - is("Hello Joe!")); - - try (Response r = target.path("/greet/greeting") - .request() - .put(Entity.entity("{\"message\" : \"Hola\"}", MediaType.APPLICATION_JSON))) { - assertThat("PUT status code", r.getStatus(), is(204)); - } - - message = target.path("/greet/Jose") - .request() - .get(GreetingMessage.class); - assertThat("hola Jose message", message.getMessage(), - is("Hola Jose!")); - } - - @Test - public void testOpenAPI() { - JsonObject jsonObject = target.path("/openapi") - .request(MediaType.APPLICATION_JSON) - .get(JsonObject.class); - JsonObject paths = jsonObject.get("paths").asJsonObject(); - - JsonPointer jp = Json.createPointer("/" + escape(SimpleAPIModelReader.MODEL_READER_PATH) + "/get/summary"); - JsonString js = (JsonString) jp.getValue(paths); - assertThat("/test/newpath GET summary did not match", js.getString(), is(SimpleAPIModelReader.SUMMARY)); - - jp = Json.createPointer("/" + escape(SimpleAPIModelReader.DOOMED_PATH)); - assertThat("/test/doomed should not appear but does", jp.containsValue(paths), is(false)); - - jp = Json.createPointer("/" + escape("/greet") + "/get/summary"); - js = (JsonString) jp.getValue(paths); - assertThat("/greet GET summary did not match", js.getString(), is("Returns a generic greeting")); - } - - private static String escape(String path) { - return path.replace("/", "~1"); - } -} diff --git a/examples/microprofile/openapi/src/test/resources/META-INF/microprofile-config.properties b/examples/microprofile/openapi/src/test/resources/META-INF/microprofile-config.properties deleted file mode 100644 index dd5725edfc4..00000000000 --- a/examples/microprofile/openapi/src/test/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) 2019, 2023 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. -# - - -# Override configuration in main source branch, so we do not use 8080 port for tests -config_ordinal=1000 -# Microprofile server properties -server.port=-1 -server.host=0.0.0.0 diff --git a/examples/microprofile/pom.xml b/examples/microprofile/pom.xml deleted file mode 100644 index dfb42e7b5eb..00000000000 --- a/examples/microprofile/pom.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples - helidon-examples-project - 4.1.0-SNAPSHOT - - pom - io.helidon.examples.microprofile - helidon-examples-microprofile-project - Helidon Examples Microprofile - - - graphql - hello-world-implicit - hello-world-explicit - static-content - security - idcs - multipart - oidc - openapi - websocket - messaging-sse - cors - tls - oci-tls-certificates - multiport - bean-validation - http-status-count-mp - lra - telemetry - - diff --git a/examples/microprofile/security/README.md b/examples/microprofile/security/README.md deleted file mode 100644 index 7636f44b946..00000000000 --- a/examples/microprofile/security/README.md +++ /dev/null @@ -1,28 +0,0 @@ - -# Helidon MP Multiple Applications with Security - -Example MicroProfile application. This has two JAX-RS applications -sharing a common resource accessed through different context roots. - -The resource has multiple endpoints, protected with different -levels of security. - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-microprofile-mp1_1-security.jar -``` - -## Endpoints - -Open either of the following in a browser. Once the page loads -click on the links to try and load endpoints restricted to -admin roles or user roles. See the example's `application.yaml` -for the list of user, passwords and roles. - -|Endpoint |Description | -|:-----------|:----------------| -|`static/helloworld`|Public page with no security| -|`other/helloworld`|Same page from second application| - diff --git a/examples/microprofile/security/pom.xml b/examples/microprofile/security/pom.xml deleted file mode 100644 index a08e65d9f87..00000000000 --- a/examples/microprofile/security/pom.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.microprofile - helidon-examples-microprofile-mp1_1-security - Helidon Examples Microprofile MP 1.1 Security - - - Microprofile 1.1 example with security - - - - io.helidon.microprofile.example.security.Main - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.smallrye - jandex - runtime - true - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/HelloWorldResource.java b/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/HelloWorldResource.java deleted file mode 100644 index 90eefd68a2b..00000000000 --- a/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/HelloWorldResource.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.microprofile.example.security; - -import io.helidon.security.Security; -import io.helidon.security.SecurityContext; -import io.helidon.security.annotations.Authenticated; -import io.helidon.security.annotations.Authorized; - -import jakarta.annotation.security.RolesAllowed; -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.Context; -import jakarta.ws.rs.core.MediaType; -import org.eclipse.microprofile.config.inject.ConfigProperty; - -/** - * A dynamic resource that shows a link to the static resource. - */ -@Path("/helloworld") -@RequestScoped -public class HelloWorldResource { - @Inject - private Security security; - @Inject - private SecurityContext securityContext; - - @Inject - @ConfigProperty(name = "server.static.classpath.context") - private String context; - - /** - * Public page (does not require authentication). - * If there is pre-emptive basic auth, it will run within a user context. - * - * @return web page with links to other resources - */ - @GET - @Produces(MediaType.TEXT_HTML) - @Authenticated(optional = true) - public String getPublic() { - return "Hello World. This is a public page with no security " - + "Allowed for admin only
      " - + "Allowed for user only
      " - + "" + context + "/resource.html allowed for a logged in user
      " - + "you are logged in as: " + securityContext.user() - + ""; - } - - /** - * Page restricted to users in "admin" role. - * - * @param securityContext Helidon security context - * @return web page with links to other resources - */ - @GET - @Path("/admin") - @Produces(MediaType.TEXT_HTML) - @Authenticated - @Authorized - @RolesAllowed("admin") - public String getAdmin(@Context SecurityContext securityContext) { - return "Hello World. You may want to check " - + "" + context + "/resource.html
      " - + "you are logged in as: " + securityContext.user() - + ""; - } - - /** - * Page restricted to users in "user" role. - * - * @param securityContext Helidon security context - * @return web page with links to other resources - */ - @GET - @Path("/user") - @Produces(MediaType.TEXT_HTML) - @Authenticated - @Authorized - @RolesAllowed("user") - public String getUser(@Context SecurityContext securityContext) { - return "Hello World. You may want to check " - + "" + context + "/resource.html
      " - + "you are logged in as: " + securityContext.user() - + ""; - } -} diff --git a/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/Main.java b/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/Main.java deleted file mode 100644 index d8208964207..00000000000 --- a/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/Main.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2018, 2020 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.microprofile.example.security; - -import java.util.concurrent.TimeUnit; - -import io.helidon.microprofile.server.Server; - -/** - * Main class to start the application. - * See resources/META-INF/microprofile-config.properties. - */ -public final class Main { - private Main() { - } - - /** - * Run this example. - * - * @param args command line arguments (ignored) - */ - public static void main(String[] args) { - long now = System.nanoTime(); - - Server server = Server.create(StaticContentApp.class, OtherApp.class) - .start(); - - now = System.nanoTime() - now; - System.out.println("Start server: " + TimeUnit.MILLISECONDS.convert(now, TimeUnit.NANOSECONDS)); - System.out.println("Endpoint available at http://localhost:" + server.port() + "/static/helloworld"); - System.out.println("Alternative endpoint (second application) available at http://localhost:" + server - .port() + "/other/helloworld"); - } -} diff --git a/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/OtherApp.java b/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/OtherApp.java deleted file mode 100644 index 0e4ee0f7c12..00000000000 --- a/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/OtherApp.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.microprofile.example.security; - -import java.util.Set; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.ws.rs.ApplicationPath; -import jakarta.ws.rs.core.Application; - -/** - * An example of two applications in a single MP Server. - * This is the "other" application - serving the same resource on a different context. - */ -@ApplicationScoped -@ApplicationPath("/other") -public class OtherApp extends Application { - @Override - public Set> getClasses() { - return Set.of( - HelloWorldResource.class - ); - } -} diff --git a/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/StaticContentApp.java b/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/StaticContentApp.java deleted file mode 100644 index d8666882fe6..00000000000 --- a/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/StaticContentApp.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.microprofile.example.security; - -import java.util.Set; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.ws.rs.ApplicationPath; -import jakarta.ws.rs.core.Application; - -/** - * Example JAX-RS application with static content. - */ -@ApplicationScoped -@ApplicationPath("/static") -public class StaticContentApp extends Application { - @Override - public Set> getClasses() { - return Set.of( - HelloWorldResource.class - ); - } -} diff --git a/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/package-info.java b/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/package-info.java deleted file mode 100644 index 52da3d94c29..00000000000 --- a/examples/microprofile/security/src/main/java/io/helidon/microprofile/example/security/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2018, 2020 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. - */ - -/** - * Static content example. - */ -package io.helidon.microprofile.example.security; diff --git a/examples/microprofile/security/src/main/resources/META-INF/beans.xml b/examples/microprofile/security/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 1b3fbc297cb..00000000000 --- a/examples/microprofile/security/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/microprofile/security/src/main/resources/META-INF/microprofile-config.properties b/examples/microprofile/security/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 40ae4becab8..00000000000 --- a/examples/microprofile/security/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2018, 2020 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. -# - -# web server configuration -# Use a random free port -server.port=0 - -# location on classpath (e.g. src/main/resources/WEB in maven) -server.static.classpath.location=/WEB -# this is optional, defaults to "/" -server.static.classpath.context=/static-cp -# server.static.path.location=/content -# server.static.path.context=/static-file diff --git a/examples/microprofile/security/src/main/resources/WEB/resource.html b/examples/microprofile/security/src/main/resources/WEB/resource.html deleted file mode 100644 index 70f019dab5a..00000000000 --- a/examples/microprofile/security/src/main/resources/WEB/resource.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - -Hello, this is a static resource loaded from classpath. -

      - The configuration (microprofile config): -

      
      -        server.static.classpath.location=/WEB
      -        server.static.classpath.context=/static-cp
      -    
      -

      - - - diff --git a/examples/microprofile/security/src/main/resources/application.yaml b/examples/microprofile/security/src/main/resources/application.yaml deleted file mode 100644 index 2ea4cce613c..00000000000 --- a/examples/microprofile/security/src/main/resources/application.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# -# Copyright (c) 2018, 2024 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. -# - -# As security uses a tree structure with object arrays, it is easier to define in yaml or JSON -# META-INF/microprofile-config.properties is still used for basic server configuration - - -# security for jersey is based on annotations -# security for webserver is configured here (static content) -security: - providers: - - abac: - - http-basic-auth: - realm: "helidon" - users: - - login: "jack" - password: "changeit" - roles: ["user", "admin"] - - login: "jill" - password: "changeit" - roles: ["user"] - - login: "john" - password: "changeit" - web-server: - paths: - - path: "/static-cp[/{*}]" - authenticate: true diff --git a/examples/microprofile/security/src/main/resources/logging.properties b/examples/microprofile/security/src/main/resources/logging.properties deleted file mode 100644 index c1abdd4a00f..00000000000 --- a/examples/microprofile/security/src/main/resources/logging.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2018, 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. -# - -handlers=io.helidon.logging.jul.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=[%1$tc] %4$s: %2$s - %5$s %6$s%n -.level=INFO -io.helidon.microprofile.config.level=FINEST diff --git a/examples/microprofile/static-content/README.md b/examples/microprofile/static-content/README.md deleted file mode 100644 index 083ac410377..00000000000 --- a/examples/microprofile/static-content/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Helidon MP with Static Content - -This example has a simple Hello World rest enpoint, plus -static content that is loaded from the application's classpath. -The configuration for the static content is in the -`microprofile-config.properties` file. - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-microprofile-mp1_1-static-content.jar -``` - -## Endpoints - -|Endpoint |Description | -|:-----------|:----------------| -|`helloworld`|Rest enpoint providing a link to the static content| -|`resource.html`|The static content| diff --git a/examples/microprofile/static-content/pom.xml b/examples/microprofile/static-content/pom.xml deleted file mode 100644 index c1dfca561c3..00000000000 --- a/examples/microprofile/static-content/pom.xml +++ /dev/null @@ -1,127 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.microprofile - helidon-examples-microprofile-mp1_1-static-content - Helidon Examples Microprofile MP 1.1 Static Content - - - Microprofile 1.1 example with static content - - - - io.helidon.microprofile.example.staticc.Main - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.smallrye - jandex - runtime - true - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.logging - helidon-logging-jul - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - **/*$* - io/helidon/microprofile/example/staticc/StaticContentTest.java - - - - - org.apache.maven.plugins - maven-failsafe-plugin - - - Run integration tests - integration-test - - integration-test - - - - io/helidon/microprofile/example/staticc/StaticContentTest.java - - - - - Verify integration tests - verify - - verify - - - - - - - diff --git a/examples/microprofile/static-content/src/main/java/io/helidon/microprofile/example/staticc/HelloWorldResource.java b/examples/microprofile/static-content/src/main/java/io/helidon/microprofile/example/staticc/HelloWorldResource.java deleted file mode 100644 index 5cc3eaef8eb..00000000000 --- a/examples/microprofile/static-content/src/main/java/io/helidon/microprofile/example/staticc/HelloWorldResource.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.microprofile.example.staticc; - -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 dynamic resource that shows a link to the static resource. - */ -@Path("/helloworld") -@RequestScoped -public class HelloWorldResource { - @Inject - @ConfigProperty(name = "server.static.classpath.context", defaultValue = "${EMPTY}") - private String context; - - @GET - @Produces(MediaType.TEXT_HTML) - public String getIt() { - return "Hello World. You may want to check " - + "" + context + "/resource.html" - + ""; - } -} diff --git a/examples/microprofile/static-content/src/main/java/io/helidon/microprofile/example/staticc/Main.java b/examples/microprofile/static-content/src/main/java/io/helidon/microprofile/example/staticc/Main.java deleted file mode 100644 index cacb5c04b43..00000000000 --- a/examples/microprofile/static-content/src/main/java/io/helidon/microprofile/example/staticc/Main.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2018, 2020 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.microprofile.example.staticc; - -import java.util.concurrent.TimeUnit; - -import io.helidon.microprofile.server.Server; - -/** - * Main class to start the application. - * See resources/META-INF/microprofile-config.properties. - */ -public class Main { - private static int port; - - private Main() { - } - - /** - * Run this example. - * - * @param args command line arguments (ignored) - */ - public static void main(String[] args) { - long now = System.nanoTime(); - - // everything is configured through application.yaml - Server server = Server.create(); - - now = System.nanoTime() - now; - System.out.println("Create server: " + TimeUnit.MILLISECONDS.convert(now, TimeUnit.NANOSECONDS)); - now = System.nanoTime(); - - server.start(); - - port = server.port(); - - now = System.nanoTime() - now; - System.out.println("Start server: " + TimeUnit.MILLISECONDS.convert(now, TimeUnit.NANOSECONDS)); - System.out.println("Endpoint available at http://localhost:" + port + "/helloworld"); - } - - public static int getPort() { - return port; - } -} diff --git a/examples/microprofile/static-content/src/main/java/io/helidon/microprofile/example/staticc/package-info.java b/examples/microprofile/static-content/src/main/java/io/helidon/microprofile/example/staticc/package-info.java deleted file mode 100644 index 7889402e25b..00000000000 --- a/examples/microprofile/static-content/src/main/java/io/helidon/microprofile/example/staticc/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2018, 2020 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. - */ - -/** - * Static content example. - */ -package io.helidon.microprofile.example.staticc; diff --git a/examples/microprofile/static-content/src/main/java/module-info.java.txt b/examples/microprofile/static-content/src/main/java/module-info.java.txt deleted file mode 100644 index 228e0c0fc09..00000000000 --- a/examples/microprofile/static-content/src/main/java/module-info.java.txt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2018, 2021 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. - */ - -/** - * Microprofile 1.1. static content example. - */ - // TODO disabled for now, as automatic modules don't work with e-api of jboss (number is not allowed): - /* - java.lang.module.FindException: Unable to derive module descriptor for /Users/tomas/.m2/repository/org/jboss/spec/javax/el/jboss-el-api_3.0_spec/1.0.7.Final/jboss-el-api_3.0_spec-1.0.7.Final.jar - Caused by: java.lang.IllegalArgumentException: jboss.el.api.3.0.spec: Invalid module name: '3' is not a Java identifier - */ -module io.helidon.microprofile.example.staticc { - requires jakarta.cdi; - requires jakarta.inject; - requires jakarta.ws.rs; - requires microprofile.config.api; - requires io.helidon.microprofile.server; -} diff --git a/examples/microprofile/static-content/src/main/resources/META-INF/beans.xml b/examples/microprofile/static-content/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 1b3fbc297cb..00000000000 --- a/examples/microprofile/static-content/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/microprofile/static-content/src/main/resources/META-INF/microprofile-config.properties b/examples/microprofile/static-content/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index ef43eb4c128..00000000000 --- a/examples/microprofile/static-content/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright (c) 2018, 2020 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. -# - -# web server configuration -# Use a random free port -server.port=0 - -# location on classpath (e.g. src/main/resources/WEB in maven) -server.static.classpath.location=/WEB -server.static.classpath.welcome=resource.html -# this is optional, defaults to "/" -# server.static.classpath.context=/static-cp -# server.static.path=/content -# server.static.path.context=/static-file diff --git a/examples/microprofile/static-content/src/main/resources/WEB/resource.html b/examples/microprofile/static-content/src/main/resources/WEB/resource.html deleted file mode 100644 index 90cce5429d9..00000000000 --- a/examples/microprofile/static-content/src/main/resources/WEB/resource.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - - -Hello, this is a static resource loaded from classpath. -

      - The configuration (microprofile config): -

      
      -        server.static.classpath.location=/WEB
      -    
      - -

      - Dynamic page (a hello world) can be found here: /helloworld - - - diff --git a/examples/microprofile/static-content/src/main/resources/logging.properties b/examples/microprofile/static-content/src/main/resources/logging.properties deleted file mode 100644 index a42ad7a5dde..00000000000 --- a/examples/microprofile/static-content/src/main/resources/logging.properties +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2018, 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. -# - -#All attributes details -handlers=io.helidon.logging.jul.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=[%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS.%1$tL] %4$s %3$s : %5$s%6$s%n -#All log level details -.level=INFO -# Microprofile config -# io.helidon.microprofile.config.level = FINEST -# Microprofile server startup -io.helidon.microprofile.startup.level=FINEST -org.glassfish.jersey.internal.Errors.level=SEVERE diff --git a/examples/microprofile/static-content/src/test/java/io/helidon/microprofile/example/staticc/StaticContentTest.java b/examples/microprofile/static-content/src/test/java/io/helidon/microprofile/example/staticc/StaticContentTest.java deleted file mode 100644 index d1225185889..00000000000 --- a/examples/microprofile/static-content/src/test/java/io/helidon/microprofile/example/staticc/StaticContentTest.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.microprofile.example.staticc; - -import java.io.IOException; - -import io.helidon.http.Status; - -import jakarta.enterprise.inject.se.SeContainer; -import jakarta.enterprise.inject.spi.CDI; -import jakarta.ws.rs.client.ClientBuilder; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.assertAll; - -/** - * Unit test for {@link HelloWorldResource}. - */ -class StaticContentTest { - @BeforeAll - static void initClass() throws IOException { - Main.main(new String[0]); - } - - @AfterAll - static void destroyClass() { - CDI current = CDI.current(); - ((SeContainer) current).close(); - } - - @Test - void testDynamicResource() { - String response = ClientBuilder.newClient() - .target("http://localhost:" + Main.getPort() + "/helloworld") - .request() - .get(String.class); - - assertAll("Response must be HTML and contain a ref to static resource", - () -> assertThat(response, containsString("/resource.html")), - () -> assertThat(response, containsString("Hello World")) - ); - } - - @Test - void testWelcomePage() { - try (Response response = ClientBuilder.newClient() - .target("http://localhost:" + Main.getPort()) - .request() - .accept(MediaType.TEXT_HTML_TYPE) - .get()) { - assertThat("Status should be 200", response.getStatus(), is(Status.OK_200.code())); - - String str = response.readEntity(String.class); - - assertAll( - () -> assertThat(response.getMediaType(), is(MediaType.TEXT_HTML_TYPE)), - () -> assertThat(str, containsString("server.static.classpath.location=/WEB")) - ); - } - } - - @Test - void testStaticResource() { - try (Response response = ClientBuilder.newClient() - .target("http://localhost:" + Main.getPort() + "/resource.html") - .request() - .accept(MediaType.TEXT_HTML_TYPE) - .get()) { - assertThat("Status should be 200", response.getStatus(), is(Status.OK_200.code())); - - String str = response.readEntity(String.class); - - assertAll( - () -> assertThat(response.getMediaType(), is(MediaType.TEXT_HTML_TYPE)), - () -> assertThat(str, containsString("server.static.classpath.location=/WEB")) - ); - } - } -} diff --git a/examples/microprofile/static-content/src/test/resources/logging.properties b/examples/microprofile/static-content/src/test/resources/logging.properties deleted file mode 100644 index 2c290104ca2..00000000000 --- a/examples/microprofile/static-content/src/test/resources/logging.properties +++ /dev/null @@ -1,19 +0,0 @@ -# -# Copyright (c) 2018, 2023 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. -# - -handlers=io.helidon.logging.jul.HelidonConsoleHandler -.level=INFO -org.jboss.weld.level=INFO diff --git a/examples/microprofile/telemetry/README.md b/examples/microprofile/telemetry/README.md deleted file mode 100644 index 621c9fa9e55..00000000000 --- a/examples/microprofile/telemetry/README.md +++ /dev/null @@ -1,66 +0,0 @@ -# Helidon MicroProfile Telemetry Example - -This example implements demonstrates usage of MP Telemetry Tracing. - -## Build and run - -```shell -mvn package -java -jar greeting/target/helidon-examples-microprofile-telemetry-greeting.jar -``` - -Run Jaeger tracer. If you prefer to use Docker, run in terminal: -```shell -docker run -d --name jaeger \ - -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \ - -e COLLECTOR_OTLP_ENABLED=true \ - -p 6831:6831/udp \ - -p 6832:6832/udp \ - -p 5778:5778 \ - -p 16686:16686 \ - -p 4317:4317 \ - -p 4318:4318 \ - -p 14250:14250 \ - -p 14268:14268 \ - -p 14269:14269 \ - -p 9411:9411 \ - jaegertracing/all-in-one:1.50 -``` - -If you have Jaeger all-in-one installed, use this command: - -```shell -jaeger-all-in-one --collector.zipkin.host-port=9411 --collector.otlp.enabled=true -``` - -Run the Secondary service: - -```shell -mvn package -java -jar secondary/target/helidon-examples-microprofile-telemetry-secondary.jar -``` - -## Exercise the application - -```shell -curl -X GET http://localhost:8080/greet -#Output: "Hello World!" - -curl -X GET http://localhost:8080/greet/span -#Output: {"Span":"PropagatedSpan{ImmutableSpanContext{traceId=00000000000000000000000000000000, spanId=0000000000000000, traceFlags=00, traceState=ArrayBasedTraceState{entries=[]}, remote=false, valid=false}}"} - -curl -X GET http://localhost:8080/greet/custom -``` -``` -#Output: -{ - "Custom Span": "SdkSpan{traceId=bea7da56d1fe82400af8ec0a8adb370d, spanId=57647ead5dc32ae7, parentSpanContext=ImmutableSpanContext{traceId=bea7da56d1fe82400af8ec0a8adb370d, spanId=0ca670f1e3330ea5, traceFlags=01, traceState=ArrayBasedTraceState{entries=[]}, remote=false, valid=true}, name=custom, kind=INTERNAL, attributes=AttributesMap{data={attribute=value}, capacity=128, totalAddedValues=1}, status=ImmutableStatusData{statusCode=UNSET, description=}, totalRecordedEvents=0, totalRecordedLinks=0, startEpochNanos=1683724682576003542, endEpochNanos=1683724682576006000}" -} -``` -```shell -curl -X GET http://localhost:8080/greet/outbound -#Output: Secondary - -``` - -Proceed Jaeger UI http://localhost:16686. In the top-down menu select "greeting-service" and click "Find traces". Tracing information should become available. \ No newline at end of file diff --git a/examples/microprofile/telemetry/greeting/pom.xml b/examples/microprofile/telemetry/greeting/pom.xml deleted file mode 100644 index 3985c239da6..00000000000 --- a/examples/microprofile/telemetry/greeting/pom.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../../applications/mp/pom.xml - - io.helidon.examples.microprofile - helidon-examples-microprofile-telemetry-greeting - Helidon Examples MicroProfile Telemetry Greeting - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.opentelemetry - opentelemetry-exporter-jaeger - - - io.helidon.microprofile.telemetry - helidon-microprofile-telemetry - - - io.smallrye - jandex - runtime - true - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/microprofile/telemetry/greeting/src/main/java/io/helidon/examples/microprofile/telemetry/GreetResource.java b/examples/microprofile/telemetry/greeting/src/main/java/io/helidon/examples/microprofile/telemetry/GreetResource.java deleted file mode 100644 index 48ddfae3968..00000000000 --- a/examples/microprofile/telemetry/greeting/src/main/java/io/helidon/examples/microprofile/telemetry/GreetResource.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2023 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.microprofile.telemetry; - -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.api.trace.Tracer; -import io.opentelemetry.instrumentation.annotations.WithSpan; -import jakarta.inject.Inject; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.MediaType; -import org.glassfish.jersey.server.Uri; - -/** - * A simple JAX-RS resource to greet you. Examples: - * - * Get default greeting message: - * curl -X GET http://localhost:8080/greet - * - * Get Span information: - * curl -X GET http://localhost:8080/greet/span - * - * Call secondary service: - * curl -X GET http://localhost:8080/greet/outbound - * - * Explore traces in Jaeger UI. - */ -@Path("/greet") -public class GreetResource { - - private Span span; - - private Tracer tracer; - - @Uri("http://localhost:8081/secondary") - private WebTarget target; - - @Inject - GreetResource(Span span, Tracer tracer) { - this.span = span; - this.tracer = tracer; - } - - /** - * Return a worldly greeting message. - * - * @return {@link String} - */ - @GET - @WithSpan("default") - public String getDefaultMessage() { - return "Hello World"; - } - - /** - * Create an internal custom span and return its description. - * @return {@link GreetingMessage} - */ - @GET - @Path("custom") - @Produces(MediaType.APPLICATION_JSON) - @WithSpan - public GreetingMessage useCustomSpan() { - Span span = tracer.spanBuilder("custom") - .setSpanKind(SpanKind.INTERNAL) - .setAttribute("attribute", "value") - .startSpan(); - span.end(); - - return new GreetingMessage("Custom Span" + span); - } - - /** - * Get Span info. - * - * @return {@link GreetingMessage} - */ - @GET - @Path("span") - @Produces(MediaType.APPLICATION_JSON) - @WithSpan - public GreetingMessage getSpanInfo() { - return new GreetingMessage("Span " + span.toString()); - } - - /** - * Call the secondary service running on port 8081. - * - * @return String from the secondary service. - */ - @GET - @Path("/outbound") - @WithSpan("outbound") - public String outbound() { - return target.request().accept(MediaType.TEXT_PLAIN).get(String.class); - } - -} diff --git a/examples/microprofile/telemetry/greeting/src/main/java/io/helidon/examples/microprofile/telemetry/GreetingMessage.java b/examples/microprofile/telemetry/greeting/src/main/java/io/helidon/examples/microprofile/telemetry/GreetingMessage.java deleted file mode 100644 index 6f5c7209d22..00000000000 --- a/examples/microprofile/telemetry/greeting/src/main/java/io/helidon/examples/microprofile/telemetry/GreetingMessage.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2023 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.microprofile.telemetry; - -/** - * POJO defining the greeting message content. - */ -@SuppressWarnings("unused") -public class GreetingMessage { - private String message; - - /** - * Create a new GreetingMessage instance. - */ - public GreetingMessage() { - } - - /** - * Create a new GreetingMessage instance. - * - * @param message message - */ - public GreetingMessage(String message) { - this.message = message; - } - - /** - * Gets the message value. - * - * @return message value - */ - public String getMessage() { - return message; - } - - /** - * Sets the message value. - * - * @param message message value to set - */ - public void setMessage(String message) { - this.message = message; - } -} diff --git a/examples/microprofile/telemetry/greeting/src/main/java/io/helidon/examples/microprofile/telemetry/MixedTelemetryGreetResource.java b/examples/microprofile/telemetry/greeting/src/main/java/io/helidon/examples/microprofile/telemetry/MixedTelemetryGreetResource.java deleted file mode 100644 index eae2c42ae05..00000000000 --- a/examples/microprofile/telemetry/greeting/src/main/java/io/helidon/examples/microprofile/telemetry/MixedTelemetryGreetResource.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2023 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.microprofile.telemetry; - -import io.opentelemetry.instrumentation.annotations.WithSpan; -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; - -/** - * A simple JAX-RS resource to use `io.opentelemetry` and `io.helidon.api` in mixed mode. Examples: - * - * Get mixed traces with Global tracer: - * curl -X GET http://localhost:8080/mixed - * - * Get mixed traces with an injected Helidon tracer: - * curl -X GET http://localhost:8080/mixed/injected - * - * Explore traces in Jaeger UI. - */ -@Path("/mixed") -public class MixedTelemetryGreetResource { - - private io.helidon.tracing.Tracer helidonTracerInjected; - - @Inject - MixedTelemetryGreetResource(io.helidon.tracing.Tracer helidonTracerInjected) { - this.helidonTracerInjected = helidonTracerInjected; - } - - - /** - * Create a helidon mixed span using Helidon Global tracer. - * @return {@link GreetingMessage} - */ - @GET - @Produces(MediaType.APPLICATION_JSON) - @WithSpan("mixed_parent") - public GreetingMessage mixedSpan() { - - io.helidon.tracing.Tracer helidonTracer = io.helidon.tracing.Tracer.global(); - io.helidon.tracing.Span mixedSpan = helidonTracer.spanBuilder("mixed_inner") - .kind(io.helidon.tracing.Span.Kind.SERVER) - .tag("attribute", "value") - .start(); - mixedSpan.end(); - - return new GreetingMessage("Mixed Span"); - } - - /** - * Create a helidon mixed span using injected Helidon Tracer. - * @return {@link GreetingMessage} - */ - @GET - @Path("injected") - @Produces(MediaType.APPLICATION_JSON) - @WithSpan("mixed_parent_injected") - public GreetingMessage mixedSpanInjected() { - io.helidon.tracing.Span mixedSpan = helidonTracerInjected.spanBuilder("mixed_injected_inner") - .kind(io.helidon.tracing.Span.Kind.SERVER) - .tag("attribute", "value") - .start(); - mixedSpan.end(); - - return new GreetingMessage("Mixed Span Injected"); - } -} diff --git a/examples/microprofile/telemetry/greeting/src/main/java/io/helidon/examples/microprofile/telemetry/package-info.java b/examples/microprofile/telemetry/greeting/src/main/java/io/helidon/examples/microprofile/telemetry/package-info.java deleted file mode 100644 index 23dff1e8930..00000000000 --- a/examples/microprofile/telemetry/greeting/src/main/java/io/helidon/examples/microprofile/telemetry/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2023 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. - */ - -/** - * MicroProfile Telemetry example. - */ -package io.helidon.examples.microprofile.telemetry; diff --git a/examples/microprofile/telemetry/greeting/src/main/resources/META-INF/beans.xml b/examples/microprofile/telemetry/greeting/src/main/resources/META-INF/beans.xml deleted file mode 100644 index cf179d28185..00000000000 --- a/examples/microprofile/telemetry/greeting/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/microprofile/telemetry/greeting/src/main/resources/META-INF/microprofile-config.properties b/examples/microprofile/telemetry/greeting/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 018e8845a2c..00000000000 --- a/examples/microprofile/telemetry/greeting/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,29 +0,0 @@ -# -# Copyright (c) 2023 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. -# - -# Microprofile server properties -server.port=8080 -server.host=0.0.0.0 - -# Enable the optional MicroProfile Metrics REST.request metrics -metrics.rest-request.enabled=true - -#OpenTelemtry -otel.sdk.disabled=false -otel.traces.exporter=jaeger -otel.service.name=greeting-service - -#telemetry.span.full.url=true diff --git a/examples/microprofile/telemetry/greeting/src/main/resources/logging.properties b/examples/microprofile/telemetry/greeting/src/main/resources/logging.properties deleted file mode 100644 index 95fe0b0f73d..00000000000 --- a/examples/microprofile/telemetry/greeting/src/main/resources/logging.properties +++ /dev/null @@ -1,39 +0,0 @@ -# -# Copyright (c) 2023, 2024 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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.microprofile.level=INFO -#io.helidon.common.level=INFO -#org.glassfish.jersey.level=INFO -#org.jboss.weld=INFO diff --git a/examples/microprofile/telemetry/pom.xml b/examples/microprofile/telemetry/pom.xml deleted file mode 100644 index e44c5ef2ac7..00000000000 --- a/examples/microprofile/telemetry/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - 4.0.0 - - io.helidon.examples.microprofile - helidon-examples-microprofile-project - 4.1.0-SNAPSHOT - - io.helidon.examples.telemetry - helidon-examples-microprofile-telemetry - Helidon Examples MicroProfile Telemetry - pom - - - greeting - secondary - - diff --git a/examples/microprofile/telemetry/secondary/pom.xml b/examples/microprofile/telemetry/secondary/pom.xml deleted file mode 100644 index 68a4fe5569c..00000000000 --- a/examples/microprofile/telemetry/secondary/pom.xml +++ /dev/null @@ -1,92 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../../applications/mp/pom.xml - - io.helidon.examples.microprofile - helidon-examples-microprofile-telemetry-secondary - Helidon Examples MicroProfile Telemetry Secondary service - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.microprofile.telemetry - helidon-microprofile-telemetry - - - io.opentelemetry - opentelemetry-exporter-jaeger - - - io.smallrye - jandex - runtime - true - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.microprofile.testing - helidon-microprofile-testing-junit5 - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/microprofile/telemetry/secondary/src/main/java/io/helidon/examples/microprofile/telemetry/SecondaryResource.java b/examples/microprofile/telemetry/secondary/src/main/java/io/helidon/examples/microprofile/telemetry/SecondaryResource.java deleted file mode 100644 index d003248dfd0..00000000000 --- a/examples/microprofile/telemetry/secondary/src/main/java/io/helidon/examples/microprofile/telemetry/SecondaryResource.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2023 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.microprofile.telemetry; - -import io.opentelemetry.instrumentation.annotations.WithSpan; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; - -/** - * A simple JAX-RS resource used by Telemetry Example. - */ -@Path("/secondary") -public class SecondaryResource { - - /** - * Return a secondary message. - * - * @return {@link String} - */ - @GET - @WithSpan - public String getSecondaryMessage() { - return "Secondary"; - } - -} diff --git a/examples/microprofile/telemetry/secondary/src/main/java/io/helidon/examples/microprofile/telemetry/package-info.java b/examples/microprofile/telemetry/secondary/src/main/java/io/helidon/examples/microprofile/telemetry/package-info.java deleted file mode 100644 index 23dff1e8930..00000000000 --- a/examples/microprofile/telemetry/secondary/src/main/java/io/helidon/examples/microprofile/telemetry/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2023 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. - */ - -/** - * MicroProfile Telemetry example. - */ -package io.helidon.examples.microprofile.telemetry; diff --git a/examples/microprofile/telemetry/secondary/src/main/resources/META-INF/beans.xml b/examples/microprofile/telemetry/secondary/src/main/resources/META-INF/beans.xml deleted file mode 100644 index cf179d28185..00000000000 --- a/examples/microprofile/telemetry/secondary/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/microprofile/telemetry/secondary/src/main/resources/META-INF/microprofile-config.properties b/examples/microprofile/telemetry/secondary/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index ec42ced3774..00000000000 --- a/examples/microprofile/telemetry/secondary/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2023 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. -# - -# Microprofile server properties -server.port=8081 -server.host=0.0.0.0 - -# Enable the optional MicroProfile Metrics REST.request metrics -metrics.rest-request.enabled=true - -#OpenTelemtry -otel.sdk.disabled=false -otel.traces.exporter=jaeger -otel.service.name=secondary-service - diff --git a/examples/microprofile/telemetry/secondary/src/main/resources/logging.properties b/examples/microprofile/telemetry/secondary/src/main/resources/logging.properties deleted file mode 100644 index 95fe0b0f73d..00000000000 --- a/examples/microprofile/telemetry/secondary/src/main/resources/logging.properties +++ /dev/null @@ -1,39 +0,0 @@ -# -# Copyright (c) 2023, 2024 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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.microprofile.level=INFO -#io.helidon.common.level=INFO -#org.glassfish.jersey.level=INFO -#org.jboss.weld=INFO diff --git a/examples/microprofile/tls/README.md b/examples/microprofile/tls/README.md deleted file mode 100644 index 31bceaacb7d..00000000000 --- a/examples/microprofile/tls/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Helidon MP TLS Example - -This examples shows how to configure server TLS using Helidon MP. - -Note: This example uses self-signed server certificate! - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-microprofile-tls.jar -``` -## Exercise the application -```shell -curl -k -X GET https://localhost:8080 -``` diff --git a/examples/microprofile/tls/pom.xml b/examples/microprofile/tls/pom.xml deleted file mode 100644 index 8a25029a4cb..00000000000 --- a/examples/microprofile/tls/pom.xml +++ /dev/null @@ -1,88 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../applications/mp/pom.xml - - - io.helidon.examples.microprofile - helidon-examples-microprofile-tls - Helidon Examples Microprofile TLS - - - Microprofile example that configures TLS - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.logging - helidon-logging-jul - runtime - - - io.smallrye - jandex - runtime - true - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - - diff --git a/examples/microprofile/tls/src/main/java/io/helidon/microprofile/example/tls/GreetResource.java b/examples/microprofile/tls/src/main/java/io/helidon/microprofile/example/tls/GreetResource.java deleted file mode 100644 index 766eec1a4f5..00000000000 --- a/examples/microprofile/tls/src/main/java/io/helidon/microprofile/example/tls/GreetResource.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.microprofile.example.tls; - -import jakarta.enterprise.context.RequestScoped; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; - -/** - * A simple JAX-RS resource to greet you. Examples: - * - * Get default greeting message: - * curl -X GET https://localhost:8080 - * - * The message is returned as a plain text. - */ -@Path("/") -@RequestScoped -public class GreetResource { - - /** - * Return a greeting message. - * - * @return {@link String} - */ - @GET - @Produces(MediaType.TEXT_PLAIN) - public String getDefaultMessage() { - return "Hello user!"; - } - -} diff --git a/examples/microprofile/tls/src/main/java/io/helidon/microprofile/example/tls/Main.java b/examples/microprofile/tls/src/main/java/io/helidon/microprofile/example/tls/Main.java deleted file mode 100644 index ab9ad747cc8..00000000000 --- a/examples/microprofile/tls/src/main/java/io/helidon/microprofile/example/tls/Main.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2020 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.microprofile.example.tls; - -import io.helidon.microprofile.server.Server; - -/** - * Starts the server. - */ -public class Main { - - private Main() { - } - - /** - * Main method. - * - * @param args args - */ - public static void main(String[] args) { - startServer(); - } - - static Server startServer() { - return Server.create().start(); - } - -} diff --git a/examples/microprofile/tls/src/main/java/io/helidon/microprofile/example/tls/package-info.java b/examples/microprofile/tls/src/main/java/io/helidon/microprofile/example/tls/package-info.java deleted file mode 100644 index c2d678945b7..00000000000 --- a/examples/microprofile/tls/src/main/java/io/helidon/microprofile/example/tls/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020 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. - */ - -/** - * Quickstart MicroProfile example. - */ -package io.helidon.microprofile.example.tls; diff --git a/examples/microprofile/tls/src/main/resources/META-INF/beans.xml b/examples/microprofile/tls/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 4a5ec955fb7..00000000000 --- a/examples/microprofile/tls/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/microprofile/tls/src/main/resources/META-INF/microprofile-config.properties b/examples/microprofile/tls/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 2c3978a78bc..00000000000 --- a/examples/microprofile/tls/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2020, 2024 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. -# - -# Microprofile server properties -server.port=8080 -server.host=0.0.0.0 - -#Truststore setup -server.tls.trust.keystore.resource.resource-path=server.p12 -server.tls.trust.keystore.passphrase=changeit -server.tls.trust.keystore.trust-store=true - -#Keystore with private key and server certificate -server.tls.private-key.keystore.resource.resource-path=server.p12 -server.tls.private-key.keystore.passphrase=changeit diff --git a/examples/microprofile/tls/src/main/resources/logging.properties b/examples/microprofile/tls/src/main/resources/logging.properties deleted file mode 100644 index 84a691d1515..00000000000 --- a/examples/microprofile/tls/src/main/resources/logging.properties +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2020, 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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 - diff --git a/examples/microprofile/tls/src/main/resources/server.p12 b/examples/microprofile/tls/src/main/resources/server.p12 deleted file mode 100644 index d2599833af58546bbd5fb7633ef73d46a1d8ccbd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4202 zcmY+GbyO1$_r|xep^O?5(kVj*gN<$^1SAxY6qL~oiUWiZItgh(=?-ZrX-0{Jj7|Xo zDG?En9Fni+{C@BEd)`0px#xbK``kaDb5VGh0|-cl!o#@8DG*^=VI*qc6<`h?1_R?^ zRDbbR6dqFWKN2JnjEBVk#W8;?f}HaIT~tsYC5UM7$k`?ssDj*e6v*1t*() zRf%JofaNgvvT5UyqN?i0l`wlXJ zEN@?7UMn7aS(o@hVdShUyZ1OL9VW*GkTx>juHpziunF#jJ5+HWU~z&e{30FstUqtQ znA>3yPib>z-%DZsZ14T*ebdMu1Nix`haT#46%S627O$PCVhwXoQUkvw+zQL;))r)r z-SX-m?K#F(ga*0q7Dio<8X3;tl_Oo#MmB1y>lucmSa{(Es*Lqr1kTTF!>piC9gZ1k zxU0oJ%{?&lSw`8fJ1^snY?CX@POndLqS0L9XUtMCNP{S`OZ(@seOwBR_5syfXE5=#u_}%mekOg&>U3QH=z?I1 za0x?n4<3}W;P5%5?f?f2TNeH17hJ|>hBhw7w-ig=7fNy3Zpl+s&$(`sQziN{iI!C zg{`y6N?7!V%vJbp{bG6odT3)O7nLbFzBjT)*Vy-Spb8#zvG{6A{(X)wg)W=cHCbKZ zRUSdZxFJB!v&B(`29InQTYM6a<<%(a$m-t@Q9MZ6;pdeVt*=oc`q;aC$_8eQ&f6hl?-3hysp?{{N`M-uzjC?V|O1Q%J`{<)ynt4XmGQB*KpqWC3lNP zM9+X9tT3JwZ=JMMMu*7hKu$hj%`|pn9YH-5J{_QHmO?PVtm>5Q z5$4;qU63J9SNncvhg>2p{XiDUU*OxlS!o}>O$QWEL~SKuEL9lB?Jbe0%_sM~w&}hL zthH_Fa$5gZrro_}TF-{-NRDf`a6JHj*Oa#Th|B>D*jDOxwwAncU&ITrM=Yea<;@v@Lw&5gUx1I}G>Ye6#E519Uo&!cx93Jnqh!%&aS2&TX-O0c54HSf=?Zxc z9;){j-2njsf1B#R3J@ho4*hRt1IbZrV1_`%G<<JTjb zl`*sJZC~YT?}r@uF^uW?!|6J>+1&+^CEmE_W?Fpi?)Z~o-QuRt8lz(hW&ja+M@^-F@!$Dh3Dmq971p%Cl)q&4#VU6;}M zCFNT5RNRvdez`GajOhM^+GNU@aQPRPi$+MOu-P)RWNK<$BxjLsoW|wa!AMD@@=QO^ zqBYUCt-X$FIH{WdLco88jo4qRIK+_oTNYtaeB0WXhhJo$k+ua_Gyne4TY4Ism-C(p z$cZo6)6Spnsv~?u%vxW`*(_3fhkwHTh!d;N^ynO!)gvB0=-@~Y)(1n$Vf;fjj=otA~5Em zIGJPwB_M^?fyqM=DIa6SH?D|_Isb~PcY$4>zekAg$pc{M&fny(MJ{nNv-U~&EL`(C zC2$I8LOQ$Te)MdrvL1yh=Gf>6RSu+54gE5rUVIyW*rGZP+`T;1Z|s>xQ7IA3KP5bt zZCB;$YZOn}I#5{hd=Yg`nat+OaD)izb+=fFnuz}753hoY0^y~> zjiiO}w%ju)=mm4M@FdRf$yXmz*;cW!R7kH;gyg{Is)g*@Qyy-0;ZoyR3Rd`-mzyE1 z0PE!4f*Z!yiX=L7VTI0)_~1tgZU8At^93o+e4E>eH5}aybjnY5F&A#HBDP=9(t1`> zM1-r*QLrb(dD>xCTJGyHQu~?&Zs&Qw_>p`m5*2tiOY4@{61e#2lHx-q$J|b-8m_-k z(g4)^tTR2F;kUHt)0g`fQj}A7fLub>h9xloS5~_j+PN-y*Lx4?5kaXr#ua zK?<@tn3~0o)MV#2dUKn(N!y_fE@AyF{J(G;6XQ zVEev$mOd=^{qxmUr+DqOGd(EQxqLF!g9vnWEHeBx1(_@(WB7XIPp!>l1s9>Xt5JsF zNGIQ`vb`-KHT`yo8FKmbiIw2An_oIfqwUB0uV%9f6=5>8xd6j6P|5s?KT8?fN~-2G zWs@*e<}zz2Y?TW%&&AnEGCf3mgH(p;+#Cmd*V2l{%h^QRuPHAf$8vX$;*+MdG8>T`U%$%eDqGSU z!orm_YoI^H`NE%gRO%SW^t_DlUP_?zO{|dQtN3N;L?92H+10l38bpEjm}{$MdqR0l zm`m7Iyxy!;%IW4PxiIhO0_y7uFAv~u%NlLQ7URrLVb?5O zvK4f8`*F}d?{Kz%#59;vOh^7sa=mNPmQiEmOLWnA#M%Ht9NSldj`2T}h_+f&8n}$1 zbpjrCib)&#Z|o(m;tCwcXFApf{(cg+l86vJ0W)d6Po7f~;0S4YJ4ms=2pBDGf2U-q z$og}BJa`|pZrr1$TXK#K8L4`haBagWb*cjYHY&E7*I^^NoPMX>j7cyCS9`gcGG$-; zD)n`07Ps3j_ly{YqD#9%;#|4>C4lnI(rJV)s$C@}O`R7Oybuld5GswgZ|_sjc#E?Y zZkf09>*!vOUj)%>wIU@bS?d+lup#A$S;SFU(*Vk19xIZhaLd+iar@ATYN{&|q#BMmQ8)Z$8*h->UQJMsWCX<0L4QcXDidTUhc;5Y`(r8_fu13qRAAUeLqWEgTX<@UMnO02xSkrZ811eHGnXR4|M}p#UDhGFgiIk~| z4;moL1&@OIqL8}8IS!iks!4GVTs(HQUx-JmF?Hn@cMdL zXHphCYHdyvWnHnmWVJAGC=4&6eU-gsjfIoDhU~|KGW}@n+by<6K)@V=R89S zD1UX>{Z9N5P_G*3v{q5vwO!ddDMnus6d6{h;qp5(qIl0FuQmJRTeNyM@y$xh1?kz& z!iYxgm6EDcUOM#7ouKe0U>o1|^xdQ?(|{g6=MefMp1Ga`O|8a&!ls_Qm;v6$tiL1u zedDvhiD@w@6`ivmx&0D{nN?P9@d2{f<3L_~sV2f*qbt>1MIm;Fo)4KHhj*CS0?LZo z@DB)A;BG(fw{c-Tuy*uZI!v9nS>Q>Frb~iOMNI2Cq25K2POIkPSNQMy3%Gs diff --git a/examples/microprofile/tls/src/test/java/io/helidon/microprofile/example/tls/TlsTest.java b/examples/microprofile/tls/src/test/java/io/helidon/microprofile/example/tls/TlsTest.java deleted file mode 100644 index 3b882592a07..00000000000 --- a/examples/microprofile/tls/src/test/java/io/helidon/microprofile/example/tls/TlsTest.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2020, 2021 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.microprofile.example.tls; - -import java.net.URI; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; - -import io.helidon.microprofile.server.Server; - -import jakarta.ws.rs.client.Client; -import jakarta.ws.rs.client.ClientBuilder; -import jakarta.ws.rs.core.Response; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Test of the example. - */ -public class TlsTest { - - private static Client client; - static { - - try { - SSLContext sslcontext = SSLContext.getInstance("TLS"); - sslcontext.init(null, new TrustManager[]{new X509TrustManager() { - public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {} - public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {} - public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } - }}, new java.security.SecureRandom()); - - client = ClientBuilder.newBuilder() - .sslContext(sslcontext) - .build(); - } catch (Exception e) { - e.printStackTrace(); - } - } - private static Server server; - - @BeforeAll - static void initClass() { - server = Main.startServer(); - server.start(); - } - - @AfterAll - static void destroyClass() { - server.stop(); - } - - @Test - public void testTls() { - URI restUri = URI.create("https://localhost:" + server.port() + "/"); - try (Response res = client.target(restUri).request().get()) { - assertThat(res.getStatus(), is(200)); - assertThat(res.readEntity(String.class), is("Hello user!")); - } - } - -} diff --git a/examples/microprofile/tls/src/test/resources/META-INF/microprofile-config.properties b/examples/microprofile/tls/src/test/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 32b20fab0bd..00000000000 --- a/examples/microprofile/tls/src/test/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2020 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. -# - -# Microprofile server properties -server.port=0 - -config_ordinal=500 diff --git a/examples/microprofile/websocket/README.md b/examples/microprofile/websocket/README.md deleted file mode 100644 index 60300ddd9c5..00000000000 --- a/examples/microprofile/websocket/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# Helidon MP WebSocket Example - -This examples shows a simple application written using Helidon MP -that combines REST resources and WebSocket endpoints. - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-microprofile-websocket.jar -``` -[Open In browser](http://localhost:7001/web/index.html) diff --git a/examples/microprofile/websocket/pom.xml b/examples/microprofile/websocket/pom.xml deleted file mode 100644 index 852c2b6fcb1..00000000000 --- a/examples/microprofile/websocket/pom.xml +++ /dev/null @@ -1,97 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.microprofile - helidon-examples-microprofile-websocket - Helidon Examples Microprofile WebSocket - - - Microprofile example that uses websockets - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.microprofile.websocket - helidon-microprofile-websocket - - - io.helidon.logging - helidon-logging-jul - runtime - - - io.smallrye - jandex - runtime - true - - - io.helidon.microprofile.testing - helidon-microprofile-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/MessageBoardEndpoint.java b/examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/MessageBoardEndpoint.java deleted file mode 100644 index de51c01416a..00000000000 --- a/examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/MessageBoardEndpoint.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.microprofile.example.websocket; - -import java.io.IOException; -import java.util.logging.Logger; - -import jakarta.inject.Inject; -import jakarta.websocket.Encoder; -import jakarta.websocket.EndpointConfig; -import jakarta.websocket.OnClose; -import jakarta.websocket.OnError; -import jakarta.websocket.OnMessage; -import jakarta.websocket.OnOpen; -import jakarta.websocket.Session; -import jakarta.websocket.server.ServerEndpoint; - -/** - * Class MessageBoardEndpoint. - */ -@ServerEndpoint( - value = "/websocket", - encoders = { MessageBoardEndpoint.UppercaseEncoder.class } -) -public class MessageBoardEndpoint { - private static final Logger LOGGER = Logger.getLogger(MessageBoardEndpoint.class.getName()); - - @Inject - private MessageQueue messageQueue; - - /** - * OnOpen call. - * - * @param session The websocket session. - * @throws IOException If error occurs. - */ - @OnOpen - public void onOpen(Session session) throws IOException { - LOGGER.info("OnOpen called"); - } - - /** - * OnMessage call. - * - * @param session The websocket session. - * @param message The message received. - * @throws Exception If error occurs. - */ - @OnMessage - public void onMessage(Session session, String message) throws Exception { - LOGGER.info("OnMessage called '" + message + "'"); - - // Send all messages in the queue - if (message.equals("SEND")) { - while (!messageQueue.isEmpty()) { - session.getBasicRemote().sendObject(messageQueue.pop()); - } - } - } - - /** - * OnError call. - * - * @param t The throwable. - */ - @OnError - public void onError(Throwable t) { - LOGGER.info("OnError called"); - } - - /** - * OnError call. - * - * @param session The websocket session. - */ - @OnClose - public void onClose(Session session) { - LOGGER.info("OnClose called"); - } - - /** - * Uppercase encoder. - */ - public static class UppercaseEncoder implements Encoder.Text { - - @Override - public String encode(String s) { - LOGGER.info("UppercaseEncoder encode called"); - return s.toUpperCase(); - } - - @Override - public void init(EndpointConfig config) { - } - - @Override - public void destroy() { - } - } -} diff --git a/examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/MessageQueue.java b/examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/MessageQueue.java deleted file mode 100644 index 5f1dc870058..00000000000 --- a/examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/MessageQueue.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.microprofile.example.websocket; - -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; - -import jakarta.enterprise.context.ApplicationScoped; - -/** - * Class MessageQueue. - */ -@ApplicationScoped -public class MessageQueue { - - private Queue queue = new ConcurrentLinkedQueue<>(); - - /** - * Push string on stack. - * - * @param s String to push. - */ - public void push(String s) { - queue.add(s); - } - - /** - * Pop string from stack. - * - * @return The string or {@code null}. - */ - public String pop() { - return queue.poll(); - } - - /** - * Check if stack is empty. - * - * @return Outcome of test. - */ - public boolean isEmpty() { - return queue.isEmpty(); - } - - /** - * Peek at stack without changing it. - * - * @return String peeked or {@code null}. - */ - public String peek() { - return queue.peek(); - } -} diff --git a/examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/MessageQueueResource.java b/examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/MessageQueueResource.java deleted file mode 100644 index 66600887c74..00000000000 --- a/examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/MessageQueueResource.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.microprofile.example.websocket; - -import java.util.logging.Logger; - -import jakarta.inject.Inject; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; - -/** - * Class MessageQueueResource. - */ -@Path("rest") -public class MessageQueueResource { - - private static final Logger LOGGER = Logger.getLogger(MessageQueueResource.class.getName()); - - @Inject - private MessageQueue messageQueue; - - /** - * Resource to push string into queue. - * - * @param s The string. - */ - @POST - @Consumes("text/plain") - public void push(String s) { - LOGGER.info("push called '" + s + "'"); - messageQueue.push(s); - } -} diff --git a/examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/package-info.java b/examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/package-info.java deleted file mode 100644 index 7ce7ebb94a7..00000000000 --- a/examples/microprofile/websocket/src/main/java/io/helidon/microprofile/example/websocket/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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. - */ - -/** - * Helidon WebSocket example. - */ -package io.helidon.microprofile.example.websocket; diff --git a/examples/microprofile/websocket/src/main/resources/META-INF/beans.xml b/examples/microprofile/websocket/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 4a5ec955fb7..00000000000 --- a/examples/microprofile/websocket/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/microprofile/websocket/src/main/resources/WEB/index.html b/examples/microprofile/websocket/src/main/resources/WEB/index.html deleted file mode 100644 index 3a61754614d..00000000000 --- a/examples/microprofile/websocket/src/main/resources/WEB/index.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - - -

      -
      -

      -

      - -

      -

      - -

      -

      -

      History

      -
      -
      - - \ No newline at end of file diff --git a/examples/microprofile/websocket/src/main/resources/application.yaml b/examples/microprofile/websocket/src/main/resources/application.yaml deleted file mode 100644 index b0a388c6079..00000000000 --- a/examples/microprofile/websocket/src/main/resources/application.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) 2020, 2021 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: 7001 - # location on classpath (e.g. src/main/resources/WEB in maven) - static.classpath: - location: "/WEB" - context: "/web" \ No newline at end of file diff --git a/examples/microprofile/websocket/src/main/resources/logging.properties b/examples/microprofile/websocket/src/main/resources/logging.properties deleted file mode 100644 index ddbc8d6521d..00000000000 --- a/examples/microprofile/websocket/src/main/resources/logging.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2020, 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. -# - -handlers=io.helidon.logging.jul.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=[%1$tc] %4$s: %2$s - %5$s %6$s%n -.level=INFO -io.helidon.microprofile.server.level=INFO diff --git a/examples/microprofile/websocket/src/test/java/io/helidon/microprofile/example/websocket/MessageBoardTest.java b/examples/microprofile/websocket/src/test/java/io/helidon/microprofile/example/websocket/MessageBoardTest.java deleted file mode 100644 index afb8d3f8fd3..00000000000 --- a/examples/microprofile/websocket/src/test/java/io/helidon/microprofile/example/websocket/MessageBoardTest.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.microprofile.example.websocket; - -import java.io.IOException; -import java.net.URI; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.logging.Logger; - -import io.helidon.microprofile.server.ServerCdiExtension; -import io.helidon.microprofile.testing.junit5.HelidonTest; - -import jakarta.inject.Inject; -import jakarta.websocket.ClientEndpointConfig; -import jakarta.websocket.CloseReason; -import jakarta.websocket.DeploymentException; -import jakarta.websocket.Endpoint; -import jakarta.websocket.EndpointConfig; -import jakarta.websocket.MessageHandler; -import jakarta.websocket.Session; -import jakarta.ws.rs.client.Entity; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.Response; -import org.glassfish.tyrus.client.ClientManager; -import org.glassfish.tyrus.container.jdk.client.JdkClientContainer; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.fail; - -/** - * Class MessageBoardTest. - */ -@HelidonTest -class MessageBoardTest { - private static final Logger LOGGER = Logger.getLogger(MessageBoardTest.class.getName()); - private static final String[] MESSAGES = { "Whisky", "Tango", "Foxtrot" }; - - private final WebTarget webTarget; - private final ServerCdiExtension server; - private final ClientManager websocketClient = ClientManager.createClient(JdkClientContainer.class.getName()); - - @Inject - MessageBoardTest(WebTarget webTarget, ServerCdiExtension server) { - this.webTarget = webTarget; - this.server = server; - } - - @Test - public void testBoard() throws IOException, DeploymentException, InterruptedException { - // Post messages using REST resource - for (String message : MESSAGES) { - try (Response res = webTarget.path("/rest").request().post(Entity.text(message))) { - assertThat(res.getStatus(), is(204)); - LOGGER.info("Posting message '" + message + "'"); - } - } - - // Now connect to message board using WS and them back - URI websocketUri = URI.create("ws://localhost:" + server.port() + "/websocket"); - CountDownLatch messageLatch = new CountDownLatch(MESSAGES.length); - ClientEndpointConfig config = ClientEndpointConfig.Builder.create().build(); - - websocketClient.connectToServer(new Endpoint() { - @Override - public void onOpen(Session session, EndpointConfig EndpointConfig) { - try { - // Set message handler to receive messages - session.addMessageHandler(new MessageHandler.Whole() { - @Override - public void onMessage(String message) { - LOGGER.info("Client OnMessage called '" + message + "'"); - messageLatch.countDown(); - if (messageLatch.getCount() == 0) { - try { - session.close(); - } catch (IOException e) { - fail("Unexpected exception " + e); - } - } - } - }); - - // Send an initial message to start receiving - session.getBasicRemote().sendText("SEND"); - } catch (IOException e) { - fail("Unexpected exception " + e); - } - } - - @Override - public void onClose(Session session, CloseReason closeReason) { - LOGGER.info("Client OnClose called '" + closeReason + "'"); - } - - @Override - public void onError(Session session, Throwable thr) { - LOGGER.info("Client OnError called '" + thr + "'"); - - } - }, config, websocketUri); - - // Wait until all messages are received - assertThat("Message latch should have counted down to 0", - messageLatch.await(1000, TimeUnit.SECONDS), - is(true)); - } -} diff --git a/examples/openapi-tools/README.md b/examples/openapi-tools/README.md deleted file mode 100644 index c043e0cc545..00000000000 --- a/examples/openapi-tools/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# OpenApi Tools Examples - -This directory contains OpenApi Tools examples for Helidon SE/MP clients and servers. diff --git a/examples/openapi-tools/pom.xml b/examples/openapi-tools/pom.xml deleted file mode 100644 index a016026446a..00000000000 --- a/examples/openapi-tools/pom.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples - helidon-examples-project - 4.1.0-SNAPSHOT - - pom - io.helidon.examples.openapi.tools - helidon-examples-openapi-tools-project - Helidon Examples OpenApi Tools - - - - - - - diff --git a/examples/openapi-tools/quickstart.yaml b/examples/openapi-tools/quickstart.yaml deleted file mode 100644 index 534d98bef8d..00000000000 --- a/examples/openapi-tools/quickstart.yaml +++ /dev/null @@ -1,96 +0,0 @@ -# -# 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. -# - -openapi: 3.0.0 -servers: - - url: 'http://localhost:8080' -info: - description: >- - This is a sample for Helidon Quickstart project. - version: 1.0.0 - title: OpenAPI Helidon Quickstart - license: - name: Apache-2.0 - url: 'https://www.apache.org/licenses/LICENSE-2.0.html' -tags: - - name: message -paths: - /greet: - get: - tags: - - message - summary: Return a worldly greeting message. - operationId: getDefaultMessage - responses: - '200': - description: successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/Message' - /greet/greeting: - put: - tags: - - message - summary: Set the greeting to use in future messages. - operationId: updateGreeting - responses: - '200': - description: successful operation - '400': - description: No greeting provided - requestBody: - $ref: '#/components/requestBodies/Message' - '/greet/{name}': - get: - tags: - - message - summary: Return a greeting message using the name that was provided. - operationId: getMessage - parameters: - - name: name - in: path - description: the name to greet - required: true - schema: - type: string - responses: - '200': - description: successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/Message' -components: - requestBodies: - Message: - content: - application/json: - schema: - $ref: '#/components/schemas/Message' - description: Message for the user - required: true - schemas: - Message: - description: An message for the user - type: object - properties: - message: - type: string - format: int64 - greeting: - type: string - format: int64 diff --git a/examples/openapi/README.md b/examples/openapi/README.md deleted file mode 100644 index 370bf8f1f91..00000000000 --- a/examples/openapi/README.md +++ /dev/null @@ -1,36 +0,0 @@ - -# Helidon SE OpenAPI Example - -This example shows a simple greeting application, similar to the one from the -Helidon SE QuickStart, enhanced with OpenAPI support. - -Most of the OpenAPI document in this example comes from a static file packaged -with the application. - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-openapi.jar -``` - -Try the endpoints: - -```shell -curl -X GET http://localhost:8080/greet -#Output: {"message":"Hello World!"} - -curl -X GET http://localhost:8080/greet/Joe -#Output: {"message":"Hello Joe!"} - -curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}' http://localhost:8080/greet/greeting - -curl -X GET http://localhost:8080/greet/Jose -#Output: {"message":"Hola Jose!"} - -curl -X GET http://localhost:8080/openapi -#Output: [lengthy OpenAPI document] -``` - -The output describes not only then endpoints in `GreetService` as described in -the static file but also an endpoint contributed by the `SimpleAPIModelReader`. diff --git a/examples/openapi/pom.xml b/examples/openapi/pom.xml deleted file mode 100644 index 3003bf0c4b0..00000000000 --- a/examples/openapi/pom.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../applications/se/pom.xml - - io.helidon.examples - helidon-examples-openapi - Helidon Examples OpenAPI - - - Basic illustration of OpenAPI support in Helidon SE - - - - io.helidon.examples.openapi.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.http.media - helidon-http-media-jsonp - - - io.helidon.webserver.observe - helidon-webserver-observe-health - - - io.helidon.webserver.observe - helidon-webserver-observe-metrics - runtime - - - io.helidon.metrics - helidon-metrics-system-meters - runtime - - - io.helidon.logging - helidon-logging-jul - runtime - - - io.helidon.openapi - helidon-openapi - - - io.helidon.config - helidon-config-yaml - - - io.helidon.health - helidon-health-checks - - - jakarta.json - jakarta.json-api - - - org.junit.jupiter - junit-jupiter-api - test - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - io.helidon.webclient - helidon-webclient - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/openapi/src/main/java/io/helidon/examples/openapi/GreetService.java b/examples/openapi/src/main/java/io/helidon/examples/openapi/GreetService.java deleted file mode 100644 index be82d5ab07c..00000000000 --- a/examples/openapi/src/main/java/io/helidon/examples/openapi/GreetService.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.openapi; - -import java.util.Map; - -import io.helidon.config.Config; -import io.helidon.http.Status; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; - -/** - * 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 HttpService { - - /** - * The config value for the key {@code greeting}. - */ - private String greeting; - - private static final JsonBuilderFactory JSON_BF = Json.createBuilderFactory(Map.of()); - - GreetService() { - Config config = Config.global(); - this.greeting = config.get("app.greeting").asString().orElse("Ciao"); - } - - /** - * A service registers itself by updating the routine rules. - * - * @param rules the routing rules. - */ - @Override - public void routing(HttpRules 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().pathParameters().get("name"); - sendResponse(response, name); - } - - private void sendResponse(ServerResponse response, String name) { - GreetingMessage msg = new GreetingMessage(String.format("%s %s!", greeting, name)); - response.send(msg.forRest()); - } - - private void updateGreetingFromJson(JsonObject jo, ServerResponse response) { - if (!jo.containsKey(GreetingMessage.JSON_LABEL)) { - JsonObject jsonErrorObject = JSON_BF.createObjectBuilder() - .add("error", "No greeting provided") - .build(); - response.status(Status.BAD_REQUEST_400) - .send(jsonErrorObject); - return; - } - - greeting = GreetingMessage.fromRest(jo).getMessage(); - response.status(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) { - JsonObject jo = request.content().as(JsonObject.class); - updateGreetingFromJson(jo, response); - } - -} diff --git a/examples/openapi/src/main/java/io/helidon/examples/openapi/GreetingMessage.java b/examples/openapi/src/main/java/io/helidon/examples/openapi/GreetingMessage.java deleted file mode 100644 index 205b766133b..00000000000 --- a/examples/openapi/src/main/java/io/helidon/examples/openapi/GreetingMessage.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2019, 2021 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.openapi; - -import java.util.Collections; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import jakarta.json.JsonObjectBuilder; - -/** - * POJO for the greeting message exchanged between the server and the client. - */ -public class GreetingMessage { - - /** - * Label for tagging a {@code GreetingMessage} instance in JSON. - */ - public static final String JSON_LABEL = "greeting"; - - private static final JsonBuilderFactory JSON_BF = Json.createBuilderFactory(Collections.emptyMap()); - - private String message; - - /** - * Create a new greeting with the specified message content. - * - * @param message the message to store in the greeting - */ - public GreetingMessage(String message) { - this.message = message; - } - - /** - * Returns the message value. - * - * @return the message - */ - public String getMessage() { - return message; - } - - /** - * Sets the message value. - * - * @param message value to be set - */ - public void setMessage(String message) { - this.message = message; - } - - /** - * Converts a JSON object (typically read from the request payload) - * into a {@code GreetingMessage}. - * - * @param jsonObject the {@link JsonObject} to convert. - * @return {@code GreetingMessage} set according to the provided object - */ - public static GreetingMessage fromRest(JsonObject jsonObject) { - return new GreetingMessage(jsonObject.getString(JSON_LABEL)); - } - - /** - * Prepares a {@link JsonObject} corresponding to this instance. - * - * @return {@code JsonObject} representing this {@code GreetingMessage} instance - */ - public JsonObject forRest() { - JsonObjectBuilder builder = JSON_BF.createObjectBuilder(); - return builder.add(JSON_LABEL, message) - .build(); - } -} diff --git a/examples/openapi/src/main/java/io/helidon/examples/openapi/Main.java b/examples/openapi/src/main/java/io/helidon/examples/openapi/Main.java deleted file mode 100644 index be2254d788c..00000000000 --- a/examples/openapi/src/main/java/io/helidon/examples/openapi/Main.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.openapi; - -import io.helidon.config.Config; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.http.HttpRouting; - -/** - * Simple Hello World rest application. - */ -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) { - WebServerConfig.Builder builder = WebServer.builder(); - setup(builder); - WebServer server = builder.build().start(); - System.out.println("WEB server is up! http://localhost:" + server.port() + "/greet"); - } - - /** - * Set up the server. - * - * @param server server builder - */ - static void setup(WebServerConfig.Builder server) { - - // load logging configuration - LogConfig.configureRuntime(); - - // By default, this will pick up application.yaml from the classpath - Config config = Config.create(); - Config.global(config); - - server.config(config.get("server")) - .routing(Main::routing); - } - - /** - * Set up routing. - * - * @param routing routing builder - */ - static void routing(HttpRouting.Builder routing) { - routing.register("/greet", new GreetService()); - } - -} diff --git a/examples/openapi/src/main/java/io/helidon/examples/openapi/package-info.java b/examples/openapi/src/main/java/io/helidon/examples/openapi/package-info.java deleted file mode 100644 index 7f41df26093..00000000000 --- a/examples/openapi/src/main/java/io/helidon/examples/openapi/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2019, 2021 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 application showing support for OpenAPI in Helidon SE - *

      - * Start with {@link io.helidon.examples.openapi.Main} class. - * - * @see io.helidon.examples.openapi.Main - */ -package io.helidon.examples.openapi; diff --git a/examples/openapi/src/main/resources/META-INF/openapi.yml b/examples/openapi/src/main/resources/META-INF/openapi.yml deleted file mode 100644 index b2785566ceb..00000000000 --- a/examples/openapi/src/main/resources/META-INF/openapi.yml +++ /dev/null @@ -1,77 +0,0 @@ -# -# Copyright (c) 2019, 2023 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. -# ---- -openapi: 3.0.0 -info: - title: Helidon SE Quickstart Example - description: A very simple application to reply with friendly greetings - version: 1.0.0 - -servers: - - url: http://localhost:8080 - description: Local test server - -paths: - /greet: - get: - summary: Returns a generic greeting - description: Greets the user generically - responses: - default: - description: Simple JSON containing the greeting - content: - application/json: - schema: - $ref: '#/components/schemas/GreetingMessage' - /greet/greeting: - put: - summary: Set the greeting prefix - description: Permits the client to set the prefix part of the greeting ("Hello") - requestBody: - description: Conveys the new greeting prefix to use in building greetings - content: - application/json: - schema: - $ref: '#/components/schemas/GreetingMessage' - examples: - greeting: - summary: Example greeting message to update - value: { "greeting": "Hola" } - responses: - "204": - description: Updated - /greet/{name}: - get: - summary: Returns a personalized greeting - parameters: - - name: name - in: path - required: true - schema: - type: string - responses: - default: - description: Simple JSON containing the greeting - content: - application/json: - schema: - $ref: '#/components/schemas/GreetingMessage' -components: - schemas: - GreetingMessage: - properties: - message: - type: string diff --git a/examples/openapi/src/main/resources/application.yaml b/examples/openapi/src/main/resources/application.yaml deleted file mode 100644 index ced90e2c47e..00000000000 --- a/examples/openapi/src/main/resources/application.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) 2019, 2023 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. -# - -app: - greeting: "Hello" - -server: - port: 8080 - host: 0.0.0.0 diff --git a/examples/openapi/src/main/resources/logging.properties b/examples/openapi/src/main/resources/logging.properties deleted file mode 100644 index 6f4d5ad5ffd..00000000000 --- a/examples/openapi/src/main/resources/logging.properties +++ /dev/null @@ -1,34 +0,0 @@ -# -# Copyright (c) 2018, 2024 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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.helidon.openapi.OpenAPISupport.level=FINER diff --git a/examples/openapi/src/test/java/io/helidon/examples/openapi/MainTest.java b/examples/openapi/src/test/java/io/helidon/examples/openapi/MainTest.java deleted file mode 100644 index de2da0910ef..00000000000 --- a/examples/openapi/src/test/java/io/helidon/examples/openapi/MainTest.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.openapi; - -import java.util.Map; - -import io.helidon.common.media.type.MediaTypes; -import io.helidon.http.Status; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import jakarta.json.JsonPointer; -import jakarta.json.JsonString; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -@ServerTest -public class MainTest { - - private static final JsonBuilderFactory JSON_BF = Json.createBuilderFactory(Map.of()); - private static final JsonObject TEST_JSON_OBJECT = JSON_BF.createObjectBuilder() - .add("greeting", "Hola") - .build(); - - private final Http1Client client; - - public MainTest(Http1Client client) { - this.client = client; - } - - @SetUpServer - static void setup(WebServerConfig.Builder server) { - Main.setup(server); - } - - @Test - public void testHelloWorld() { - try (Http1ClientResponse response = client.get("/greet").request()) { - JsonObject jsonObject = response.as(JsonObject.class); - assertThat(jsonObject.getString("greeting"), is("Hello World!")); - } - - try (Http1ClientResponse response = client.get("/greet/Joe").request()) { - JsonObject jsonObject = response.as(JsonObject.class); - assertThat(jsonObject.getString("greeting"), is("Hello Joe!")); - } - - try (Http1ClientResponse response = client.put("/greet/greeting").submit(TEST_JSON_OBJECT)) { - assertThat(response.status().code(), is(204)); - } - - try (Http1ClientResponse response = client.get("/greet/Joe").request()) { - JsonObject jsonObject = response.as(JsonObject.class); - assertThat(jsonObject.getString("greeting"), is("Hola Joe!")); - } - - try (Http1ClientResponse response = client.get("/observe/health").request()) { - assertThat(response.status(), is(Status.NO_CONTENT_204)); - } - - try (Http1ClientResponse response = client.get("/observe/metrics").request()) { - assertThat(response.status().code(), is(200)); - } - } - - @Test - public void testOpenAPI() { - JsonObject jsonObject = client.get("/openapi") - .accept(MediaTypes.APPLICATION_JSON) - .requestEntity(JsonObject.class); - JsonObject paths = jsonObject.getJsonObject("paths"); - - JsonPointer jp = Json.createPointer("/" + escape("/greet/greeting") + "/put/summary"); - JsonString js = (JsonString) jp.getValue(paths); - assertThat("/greet/greeting.put.summary not as expected", js.getString(), is("Set the greeting prefix")); - } - - private static String escape(String path) { - return path.replace("/", "~1"); - } - -} diff --git a/examples/pom.xml b/examples/pom.xml deleted file mode 100644 index 58b5b6f68cd..00000000000 --- a/examples/pom.xml +++ /dev/null @@ -1,80 +0,0 @@ - - - - 4.0.0 - - io.helidon - helidon-project - 4.1.0-SNAPSHOT - - io.helidon.examples - helidon-examples-project - Helidon Examples - pom - - - true - true - true - true - true - true - - - - config - cors - dbclient - employee-app - graphql - health - integrations - jbatch - logging - media - messaging - metrics - microprofile - openapi - openapi-tools - quickstarts - security - todo-app - translator-app - webclient - webserver - - - - - - - org.codehaus.mojo - exec-maven-plugin - - ${mainClass} - - - - - - - diff --git a/examples/quickstarts/README.md b/examples/quickstarts/README.md deleted file mode 100644 index 83f2f7d6eec..00000000000 --- a/examples/quickstarts/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Helidon Examples Quickstart - -These are the examples used by the Helidon Getting Started guide, and -the quickstart Maven archetypes. All examples implement the same -simple greeting service, one using Helidon MP and one using Helidon SE. - -The `archetypes` directory contains scripts for building the Maven -archetypes from these examples. diff --git a/examples/quickstarts/helidon-quickstart-mp/.dockerignore b/examples/quickstarts/helidon-quickstart-mp/.dockerignore deleted file mode 100644 index c8b241f2215..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -target/* \ No newline at end of file diff --git a/examples/quickstarts/helidon-quickstart-mp/.gitignore b/examples/quickstarts/helidon-quickstart-mp/.gitignore deleted file mode 100644 index 594f3abf63c..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -hs_err_pid* -target/ -.DS_Store -.idea/ -*.iws -*.ipr -*.iml -atlassian-ide-plugin.xml -nbactions.xml -nb-configuration.xml -.settings -.settings/ -.project -.classpath -*.swp -*~ diff --git a/examples/quickstarts/helidon-quickstart-mp/Dockerfile b/examples/quickstarts/helidon-quickstart-mp/Dockerfile deleted file mode 100644 index 0ed90957ebd..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/Dockerfile +++ /dev/null @@ -1,53 +0,0 @@ -# -# Copyright (c) 2018, 2024 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. -# - -# 1st stage, build the app -FROM container-registry.oracle.com/java/jdk-no-fee-term:21 as build - -# Install maven -WORKDIR /usr/share -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 -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 container-registry.oracle.com/java/jdk-no-fee-term:21 -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/helidon-quickstart-mp.jar ./ -COPY --from=build /helidon/target/libs ./libs - -CMD ["java", "-jar", "helidon-quickstart-mp.jar"] - -EXPOSE 8080 diff --git a/examples/quickstarts/helidon-quickstart-mp/Dockerfile.jlink b/examples/quickstarts/helidon-quickstart-mp/Dockerfile.jlink deleted file mode 100644 index ad408f6171d..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/Dockerfile.jlink +++ /dev/null @@ -1,49 +0,0 @@ -# -# Copyright (c) 2020, 2024 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. -# - -# 1st stage, build the app -FROM container-registry.oracle.com/java/jdk-no-fee-term:21 as build - -# Install maven -WORKDIR /usr/share -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 -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 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/helidon-quickstart-mp-jri ./ -ENTRYPOINT ["/bin/bash", "/helidon/bin/start"] -EXPOSE 8080 diff --git a/examples/quickstarts/helidon-quickstart-mp/Dockerfile.native b/examples/quickstarts/helidon-quickstart-mp/Dockerfile.native deleted file mode 100644 index d3e3eddc569..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/Dockerfile.native +++ /dev/null @@ -1,54 +0,0 @@ -# -# Copyright (c) 2020, 2023 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. -# - -# 1st stage, build the app -FROM ghcr.io/graalvm/graalvm-community:21.0.0-ol9 as build - -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/helidon-quickstart-mp . - -ENTRYPOINT ["./helidon-quickstart-mp"] - -EXPOSE 8080 diff --git a/examples/quickstarts/helidon-quickstart-mp/README.md b/examples/quickstarts/helidon-quickstart-mp/README.md deleted file mode 100644 index c5a0e678264..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/README.md +++ /dev/null @@ -1,162 +0,0 @@ -# Helidon Quickstart MP Example - -This example implements a simple Hello World REST service using MicroProfile. - -## Build and run - -```shell -mvn package -java -jar target/helidon-quickstart-mp.jar -``` - -## Exercise the application - -```shell -curl -X GET http://localhost:8080/greet -#Output: {"message":"Hello World!"} - -curl -X GET http://localhost:8080/greet/Joe -#Output: {"message":"Hello Joe!"} - -curl -X PUT -H "Content-Type: application/json" -d '{"message" : "Hola"}' http://localhost:8080/greet/greeting - -curl -X GET http://localhost:8080/greet/Jose -#Output: {"message":"Hola Jose!"} -``` - -## Try health and metrics - -```shell -curl -s -X GET http://localhost:8080/health -#Output: {"outcome":"UP",... - - -# Prometheus Format -curl -s -X GET http://localhost:8080/metrics -# TYPE base:gc_g1_young_generation_count gauge - -# JSON Format -curl -H 'Accept: application/json' -X GET http://localhost:8080/metrics -#Output: {"base":... -``` - -## Build the Docker Image - -```shell -docker build -t helidon-quickstart-mp . -``` - -## Start the application with Docker - -```shell -docker run --rm -p 8080:8080 helidon-quickstart-mp:latest -``` - -Exercise the application as described above - -## Deploy the application to Kubernetes - -```shell -kubectl cluster-info # Verify which cluster -kubectl get pods # Verify connectivity to cluster -kubectl create -f app.yaml # Deploy application -kubectl get service helidon-quickstart-mp # Verify deployed service -``` - -## Build a native image with GraalVM - -GraalVM allows you to compile your programs ahead-of-time into a native - executable. See https://www.graalvm.org/docs/reference-manual/aot-compilation/ - for more information. - -You can build a native executable in 2 different ways: -* With a local installation of GraalVM -* Using Docker - -### Local build - -Download Graal VM at https://www.graalvm.org/downloads. We recommend -version `23.1.0` or later. - -```shell -# Setup the environment -export GRAALVM_HOME=/path -# build the native executable -mvn package -Pnative-image -``` - -You can also put the Graal VM `bin` directory in your PATH, or pass - `-DgraalVMHome=/path` to the Maven command. - -See https://github.com/oracle/helidon-build-tools/tree/master/helidon-maven-plugin#goal-native-image - for more information. - -Start the application: - -```shell -./target/helidon-quickstart-mp -``` - -### Multi-stage Docker build - -Build the "native" Docker Image - -```shell -docker build -t helidon-quickstart-mp-native -f Dockerfile.native . -``` - -Start the application: - -```shell -docker run --rm -p 8080:8080 helidon-quickstart-mp-native:latest -``` - - -## Build a Java Runtime Image using jlink - -You can build a custom Java Runtime Image (JRI) containing the application jars and the JDK modules -on which they depend. This image also: - -* Enables Class Data Sharing by default to reduce startup time. -* Contains a customized `start` script to simplify CDS usage and support debug and test modes. - -You can build a custom JRI in two different ways: -* Local -* Using Docker - - -### Local build - -```shell -# build the JRI -mvn package -Pjlink-image -``` - -See https://github.com/oracle/helidon-build-tools/tree/master/helidon-maven-plugin#goal-jlink-image - for more information. - -Start the application: - -```shell -./target/helidon-quickstart-mp-jri/bin/start -``` - -### Multi-stage Docker build - -Build the JRI as a Docker Image - -```shell -docker build -t helidon-quickstart-mp-jri -f Dockerfile.jlink . -``` - -Start the application: - -```shell -docker run --rm -p 8080:8080 helidon-quickstart-mp-jri:latest -``` - -See the start script help: - -```shell -docker run --rm helidon-quickstart-mp-jri:latest --help -``` diff --git a/examples/quickstarts/helidon-quickstart-mp/app.yaml b/examples/quickstarts/helidon-quickstart-mp/app.yaml deleted file mode 100644 index 16dd9668e41..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/app.yaml +++ /dev/null @@ -1,57 +0,0 @@ -# -# Copyright (c) 2018, 2021 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. -# - -kind: Service -apiVersion: v1 -metadata: - name: helidon-quickstart-mp - labels: - app: helidon-quickstart-mp -spec: - type: NodePort - selector: - app: helidon-quickstart-mp - ports: - - port: 8080 - targetPort: 8080 - name: http ---- - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: helidon-quickstart-mp - labels: - app: helidon-quickstart-mp - version: v1 -spec: - replicas: 1 - selector: - matchLabels: - app: helidon-quickstart-mp - version: v1 - template: - metadata: - labels: - app: helidon-quickstart-mp - version: v1 - spec: - containers: - - name: helidon-quickstart-mp - image: helidon-quickstart-mp - imagePullPolicy: IfNotPresent - ports: - - containerPort: 8080 diff --git a/examples/quickstarts/helidon-quickstart-mp/build.gradle b/examples/quickstarts/helidon-quickstart-mp/build.gradle deleted file mode 100644 index ea6f662ebad..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/build.gradle +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2018, 2024 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. - */ - -plugins { - id 'java' - id 'org.kordamp.gradle.jandex' version '0.6.0' - id 'application' -} - -group = 'io.helidon.examples' -version = '1.0-SNAPSHOT' - -description = """helidon-quickstart-mp""" - -sourceCompatibility = 21 -targetCompatibility = 21 -tasks.withType(JavaCompile) { - options.encoding = 'UTF-8' -} - -ext { - helidonversion = '4.1.0-SNAPSHOT' - mainClass='io.helidon.microprofile.cdi.Main' -} - -repositories { - mavenCentral() - mavenLocal() - gradlePluginPortal() -} - -dependencies { - // import Helidon BOM - implementation enforcedPlatform("io.helidon:helidon-dependencies:${project.helidonversion}") - implementation 'io.helidon.microprofile.bundles:helidon-microprofile' - implementation 'org.glassfish.jersey.media:jersey-media-json-binding' - - runtimeOnly 'io.smallrye:jandex' - runtimeOnly 'jakarta.activation:jakarta.activation-api' - - testImplementation 'io.helidon.microprofile.testing:helidon-microprofile-testing-junit5' - testImplementation 'org.junit.jupiter:junit-jupiter-api' - testImplementation 'org.hamcrest:hamcrest-all' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine' -} - -test { - useJUnitPlatform() -} - -// define a custom task to copy all dependencies in the runtime classpath -// into build/libs/libs -// uses built-in Copy -task copyLibs(type: Copy) { - from configurations.runtimeClasspath - into 'build/libs/libs' -} - -// add it as a dependency of built-in task 'assemble' -copyLibs.dependsOn jar -assemble.dependsOn copyLibs - -// default jar configuration -// set the main classpath -// add each jar under build/libs/libs into the classpath -jar { - archiveFileName = "${project.name}.jar" - manifest { - attributes ('Main-Class': "${project.mainClass}" , - 'Class-Path': configurations.runtimeClasspath.files.collect { "libs/$it.name" }.join(' ') - ) - } -} - -application { - mainClass = "${project.mainClass}" -} - -// This is a work-around for running unit tests. -// Gradle places resource files under ${buildDir}/resources. In order for -// beans.xml to get picked up by CDI it must be co-located with the classes. -// So we move it before running tests. -// In either case it ends up AOK in the final jar artifact -task moveBeansXML { - doLast { - ant.move file: "${buildDir}/resources/main/META-INF/beans.xml", - todir: "${buildDir}/classes/java/main/META-INF" - } -} -compileTestJava.dependsOn jandex -jar.dependsOn jandex -test.dependsOn moveBeansXML -run.dependsOn moveBeansXML diff --git a/examples/quickstarts/helidon-quickstart-mp/pom.xml b/examples/quickstarts/helidon-quickstart-mp/pom.xml deleted file mode 100644 index 1e5442e9f60..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/pom.xml +++ /dev/null @@ -1,110 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.quickstarts - helidon-quickstart-mp - Helidon Examples Quickstart MP - - - - io.helidon.microprofile.bundles - helidon-microprofile-core - - - io.helidon.microprofile.openapi - helidon-microprofile-openapi - - - io.helidon.microprofile.health - helidon-microprofile-health - - - io.helidon.microprofile.metrics - helidon-microprofile-metrics - - - io.helidon.logging - helidon-logging-jul - runtime - - - jakarta.json.bind - jakarta.json.bind-api - - - org.glassfish.jersey.media - jersey-media-json-binding - runtime - - - io.smallrye - jandex - runtime - true - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.microprofile.testing - helidon-microprofile-testing-junit5 - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/quickstarts/helidon-quickstart-mp/settings.gradle b/examples/quickstarts/helidon-quickstart-mp/settings.gradle deleted file mode 100644 index e63c2aac63a..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/settings.gradle +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) 2018, 2021 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. - */ - -rootProject.name = 'helidon-quickstart-mp' diff --git a/examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetResource.java b/examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetResource.java deleted file mode 100644 index 1e3aea63d80..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetResource.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.quickstart.mp; - -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") -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 GreetingMessage} - */ - @GET - @Produces(MediaType.APPLICATION_JSON) - public GreetingMessage getDefaultMessage() { - return createResponse("World"); - } - - /** - * Return a greeting message using the name that was provided. - * - * @param name the name to greet - * @return {@link GreetingMessage} - */ - @Path("/{name}") - @GET - @Produces(MediaType.APPLICATION_JSON) - public GreetingMessage getMessage(@PathParam("name") String name) { - return createResponse(name); - } - - /** - * Set the greeting to use in future messages. - * - * @param message 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(GreetingMessage message) { - if (message.getMessage() == null) { - GreetingMessage entity = new GreetingMessage("No greeting provided"); - return Response.status(Response.Status.BAD_REQUEST).entity(entity).build(); - } - - greetingProvider.setMessage(message.getMessage()); - return Response.status(Response.Status.NO_CONTENT).build(); - } - - private GreetingMessage createResponse(String who) { - String msg = String.format("%s %s!", greetingProvider.getMessage(), who); - - return new GreetingMessage(msg); - } -} diff --git a/examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingMessage.java b/examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingMessage.java deleted file mode 100644 index eab1bac7963..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingMessage.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2023 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.quickstart.mp; - -/** - * POJO defining the greeting message content. - */ -@SuppressWarnings("unused") -public class GreetingMessage { - private String message; - - /** - * Create a new GreetingMessage instance. - */ - public GreetingMessage() { - } - - /** - * Create a new GreetingMessage instance. - * - * @param message message - */ - public GreetingMessage(String message) { - this.message = message; - } - - /** - * Gets the message value. - * - * @return message value - */ - public String getMessage() { - return message; - } - - /** - * Sets the message value. - * - * @param message message value to set - */ - public void setMessage(String message) { - this.message = message; - } -} diff --git a/examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingProvider.java b/examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingProvider.java deleted file mode 100644 index 2eb86341bcb..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingProvider.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2018, 2021 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.quickstart.mp; - -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/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/package-info.java b/examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/package-info.java deleted file mode 100644 index 293e03bf641..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2018, 2021 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. - */ - -/** - * Quickstart MicroProfile example. - */ -package io.helidon.examples.quickstart.mp; diff --git a/examples/quickstarts/helidon-quickstart-mp/src/main/resources/META-INF/beans.xml b/examples/quickstarts/helidon-quickstart-mp/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 1b3fbc297cb..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/quickstarts/helidon-quickstart-mp/src/main/resources/META-INF/microprofile-config.properties b/examples/quickstarts/helidon-quickstart-mp/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 0828e0e8f12..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2018, 2020 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. -# - -# Application properties. This is the default greeting -app.greeting=Hello - -# Microprofile server properties -server.port=8080 -server.host=0.0.0.0 - -# Enable the optional MicroProfile Metrics REST.request metrics -metrics.rest-request.enabled=true diff --git a/examples/quickstarts/helidon-quickstart-mp/src/main/resources/META-INF/native-image/io.helidon.examples.quickstarts/helidon-quickstart-mp/native-image.properties b/examples/quickstarts/helidon-quickstart-mp/src/main/resources/META-INF/native-image/io.helidon.examples.quickstarts/helidon-quickstart-mp/native-image.properties deleted file mode 100644 index bac3f92ae57..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/src/main/resources/META-INF/native-image/io.helidon.examples.quickstarts/helidon-quickstart-mp/native-image.properties +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2023 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. -# - -Args=--initialize-at-build-time=io.helidon.examples diff --git a/examples/quickstarts/helidon-quickstart-mp/src/main/resources/logging.properties b/examples/quickstarts/helidon-quickstart-mp/src/main/resources/logging.properties deleted file mode 100644 index d19bc389df1..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/src/main/resources/logging.properties +++ /dev/null @@ -1,39 +0,0 @@ -# -# Copyright (c) 2018, 2024 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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.microprofile.level=INFO -#io.helidon.common.level=INFO -#org.glassfish.jersey.level=INFO -#org.jboss.weld=INFO diff --git a/examples/quickstarts/helidon-quickstart-mp/src/test/java/io/helidon/examples/quickstart/mp/MainTest.java b/examples/quickstarts/helidon-quickstart-mp/src/test/java/io/helidon/examples/quickstart/mp/MainTest.java deleted file mode 100644 index 674aa4e8b8f..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/src/test/java/io/helidon/examples/quickstart/mp/MainTest.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.quickstart.mp; - -import io.helidon.microprofile.testing.junit5.HelidonTest; - -import jakarta.inject.Inject; -import jakarta.ws.rs.client.Entity; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -@HelidonTest -class MainTest { - private final WebTarget target; - - @Inject - MainTest(WebTarget target) { - this.target = target; - } - - @Test - void testHelloWorld() { - - GreetingMessage message = target.path("/greet") - .request() - .get(GreetingMessage.class); - assertThat("default message", message.getMessage(), - is("Hello World!")); - - message = target.path("/greet/Joe") - .request() - .get(GreetingMessage.class); - assertThat("hello Joe message", message.getMessage(), - is("Hello Joe!")); - - try (Response r = target.path("/greet/greeting") - .request() - .put(Entity.entity("{\"message\" : \"Hola\"}", MediaType.APPLICATION_JSON))) { - assertThat("PUT status code", r.getStatus(), is(204)); - } - - message = target.path("/greet/Jose") - .request() - .get(GreetingMessage.class); - assertThat("hola Jose message", message.getMessage(), - is("Hola Jose!")); - } - @Test - void testMetrics() { - try (Response r = target.path("/metrics") - .request() - .get()) { - assertThat("GET metrics status code", r.getStatus(), is(200)); - } - } - - @Test - void testHealth() { - try (Response r = target.path("/health") - .request() - .get()) { - assertThat("GET health status code", r.getStatus(), is(200)); - } - } -} diff --git a/examples/quickstarts/helidon-quickstart-mp/src/test/resources/META-INF/microprofile-config.properties b/examples/quickstarts/helidon-quickstart-mp/src/test/resources/META-INF/microprofile-config.properties deleted file mode 100644 index 4894cc74437..00000000000 --- a/examples/quickstarts/helidon-quickstart-mp/src/test/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) 2018, 2023 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. -# - - -# Override configuration to use a random port for the unit tests -config_ordinal=1000 -# Microprofile server properties -server.port=-1 -server.host=0.0.0.0 diff --git a/examples/quickstarts/helidon-quickstart-se/.dockerignore b/examples/quickstarts/helidon-quickstart-se/.dockerignore deleted file mode 100644 index c8b241f2215..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -target/* \ No newline at end of file diff --git a/examples/quickstarts/helidon-quickstart-se/.gitignore b/examples/quickstarts/helidon-quickstart-se/.gitignore deleted file mode 100644 index 241e8042d94..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -hs_err_pid* -target/ -.DS_Store -.idea/ -*.iws -*.ipr -*.iml -atlassian-ide-plugin.xml -nbactions.xml -nb-configuration.xml -.settings -.settings/ -.project -.classpath -*.swp -*~ \ No newline at end of file diff --git a/examples/quickstarts/helidon-quickstart-se/Dockerfile b/examples/quickstarts/helidon-quickstart-se/Dockerfile deleted file mode 100644 index b83351760de..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/Dockerfile +++ /dev/null @@ -1,54 +0,0 @@ -# -# Copyright (c) 2018, 2024 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. -# - -# 1st stage, build the app -FROM container-registry.oracle.com/java/jdk-no-fee-term:21 as build - -# Install maven -WORKDIR /usr/share -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 -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 container-registry.oracle.com/java/jdk-no-fee-term:21 -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/helidon-quickstart-se.jar ./ -COPY --from=build /helidon/target/libs ./libs - -CMD ["java", "-jar", "helidon-quickstart-se.jar"] - -EXPOSE 8080 diff --git a/examples/quickstarts/helidon-quickstart-se/Dockerfile.jlink b/examples/quickstarts/helidon-quickstart-se/Dockerfile.jlink deleted file mode 100644 index 7b4c37eaf7f..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/Dockerfile.jlink +++ /dev/null @@ -1,49 +0,0 @@ -# -# Copyright (c) 2020, 2024 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. -# - -# 1st stage, build the app -FROM container-registry.oracle.com/java/jdk-no-fee-term:21 as build - -# Install maven -WORKDIR /usr/share -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 -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 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/helidon-quickstart-se-jri ./ -ENTRYPOINT ["/bin/bash", "/helidon/bin/start"] -EXPOSE 8080 diff --git a/examples/quickstarts/helidon-quickstart-se/Dockerfile.native b/examples/quickstarts/helidon-quickstart-se/Dockerfile.native deleted file mode 100644 index 991ca332494..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/Dockerfile.native +++ /dev/null @@ -1,54 +0,0 @@ -# -# Copyright (c) 2019, 2023 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. -# - -# 1st stage, build the app -FROM ghcr.io/graalvm/graalvm-community:21.0.0-ol9 as build - -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/helidon-quickstart-se . - -ENTRYPOINT ["./helidon-quickstart-se"] - -EXPOSE 8080 diff --git a/examples/quickstarts/helidon-quickstart-se/README.md b/examples/quickstarts/helidon-quickstart-se/README.md deleted file mode 100644 index bbb38bcc9ba..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/README.md +++ /dev/null @@ -1,161 +0,0 @@ -# Helidon Quickstart SE Example - -This project implements a simple Hello World REST service using Helidon SE. - -## Build and run - -```shell -mvn package -java -jar target/helidon-quickstart-se.jar -``` - -## Exercise the application - -```shell -curl -X GET http://localhost:8080/greet -#Output: {"message":"Hello World!"} - -curl -X GET http://localhost:8080/greet/Joe -#Output: {"message":"Hello Joe!"} - -curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}' http://localhost:8080/greet/greeting - -curl -X GET http://localhost:8080/greet/Jose -#Output: {"message":"Hola Jose!"} -``` - -## Try health and metrics - -```shell -curl -s -X GET http://localhost:8080/observe/health -#Output: {"outcome":"UP",... - -# Prometheus Format -curl -s -X GET http://localhost:8080/observe/metrics -# TYPE base:gc_g1_young_generation_count gauge - -# JSON Format -curl -H 'Accept: application/json' -X GET http://localhost:8080/observe/metrics -#Output: {"base":... - -``` - -## Build the Docker Image - -```shell -docker build -t helidon-quickstart-se . -``` - -## Start the application with Docker - -```shell -docker run --rm -p 8080:8080 helidon-quickstart-se:latest -``` - -Exercise the application as described above - -## Deploy the application to Kubernetes - -```shell -kubectl cluster-info # Verify which cluster -kubectl get pods # Verify connectivity to cluster -kubectl create -f app.yaml # Deply application -kubectl get service helidon-quickstart-se # Get service info -``` - -## Build a native image with GraalVM - -GraalVM allows you to compile your programs ahead-of-time into a native - executable. See https://www.graalvm.org/docs/reference-manual/aot-compilation/ - for more information. - -You can build a native executable in 2 different ways: -* With a local installation of GraalVM -* Using Docker - -### Local build - -Download Graal VM at https://www.graalvm.org/downloads. We recommend -version `23.1.0` or later. - -```shell -# Setup the environment -export GRAALVM_HOME=/path -# build the native executable -mvn package -Pnative-image -``` - -You can also put the Graal VM `bin` directory in your PATH, or pass - `-DgraalVMHome=/path` to the Maven command. - -See https://github.com/oracle/helidon-build-tools/tree/master/helidon-maven-plugin#goal-native-image - for more information. - -Start the application: - -```shell -./target/helidon-quickstart-se -``` - -### Multi-stage Docker build - -Build the "native" Docker Image - -```shell -docker build -t helidon-quickstart-se-native -f Dockerfile.native . -``` - -Start the application: - -```shell -docker run --rm -p 8080:8080 helidon-quickstart-se-native:latest -``` - -## Build a Java Runtime Image using jlink - -You can build a custom Java Runtime Image (JRI) containing the application jars and the JDK modules -on which they depend. This image also: - -* Enables Class Data Sharing by default to reduce startup time. -* Contains a customized `start` script to simplify CDS usage and support debug and test modes. - -You can build a custom JRI in two different ways: -* Local -* Using Docker - - -### Local build - -```shell -# build the JRI -mvn package -Pjlink-image -``` - -See https://github.com/oracle/helidon-build-tools/tree/master/helidon-maven-plugin#goal-jlink-image - for more information. - -Start the application: - -```shell -./target/helidon-quickstart-se-jri/bin/start -``` - -### Multi-stage Docker build - -Build the JRI as a Docker Image - -```shell -docker build -t helidon-quickstart-se-jri -f Dockerfile.jlink . -``` - -Start the application: - -```shell -docker run --rm -p 8080:8080 helidon-quickstart-se-jri:latest -``` - -See the start script help: - -```shell -docker run --rm helidon-quickstart-se-jri:latest --help -``` \ No newline at end of file diff --git a/examples/quickstarts/helidon-quickstart-se/app.yaml b/examples/quickstarts/helidon-quickstart-se/app.yaml deleted file mode 100644 index e5aa643c878..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/app.yaml +++ /dev/null @@ -1,57 +0,0 @@ -# -# Copyright (c) 2018, 2021 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. -# - -kind: Service -apiVersion: v1 -metadata: - name: helidon-quickstart-se - labels: - app: helidon-quickstart-se -spec: - type: NodePort - selector: - app: helidon-quickstart-se - ports: - - port: 8080 - targetPort: 8080 - name: http ---- - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: helidon-quickstart-se - labels: - app: helidon-quickstart-se - version: v1 -spec: - replicas: 1 - selector: - matchLabels: - app: helidon-quickstart-se - version: v1 - template: - metadata: - labels: - app: helidon-quickstart-se - version: v1 - spec: - containers: - - name: helidon-quickstart-se - image: helidon-quickstart-se - imagePullPolicy: IfNotPresent - ports: - - containerPort: 8080 diff --git a/examples/quickstarts/helidon-quickstart-se/build.gradle b/examples/quickstarts/helidon-quickstart-se/build.gradle deleted file mode 100644 index 5d1f00951fb..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/build.gradle +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2018, 2024 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. - */ - -plugins { - id 'java' - id 'application' -} - -group = 'io.helidon.examples' -version = '1.0-SNAPSHOT' - -description = """helidon-quickstart-se""" - -sourceCompatibility = 21 -targetCompatibility = 21 -tasks.withType(JavaCompile) { - options.encoding = 'UTF-8' -} - -ext { - helidonversion = '4.1.0-SNAPSHOT' - mainClass='io.helidon.examples.quickstart.se.Main' -} - -test { - useJUnitPlatform() -} - -repositories { - mavenCentral() - mavenLocal() -} - -dependencies { - // import Helidon BOM - implementation enforcedPlatform("io.helidon:helidon-dependencies:${project.helidonversion}") - implementation 'io.helidon.webserver:helidon-webserver' - implementation 'io.helidon.http.media:helidon-http-media-jsonp' - implementation 'io.helidon.webserver.observe:helidon-webserver-observe-health' - implementation 'io.helidon.webserver.observe:helidon-webserver-observe-metrics' - implementation 'io.helidon.config:helidon-config-yaml' - implementation 'io.helidon.health:helidon-health-checks' - - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine' - testImplementation 'io.helidon.webserver.testing.junit5:helidon-webserver-testing-junit5' - testImplementation 'io.helidon.webclient:helidon-webclient' - testImplementation 'org.hamcrest:hamcrest-all' -} - -// define a custom task to copy all dependencies in the runtime classpath -// into build/libs/libs -// uses built-in Copy -task copyLibs(type: Copy) { - from configurations.runtimeClasspath - into 'build/libs/libs' -} - -// add it as a dependency of built-in task 'assemble' -copyLibs.dependsOn jar -assemble.dependsOn copyLibs - -// default jar configuration -// set the main classpath -// add each jar under build/libs/libs into the classpath -jar { - archiveFileName = "${project.name}.jar" - manifest { - attributes ('Main-Class': "${project.mainClass}", - 'Class-Path': configurations.runtimeClasspath.files.collect { "libs/$it.name" }.join(' ') - ) - } -} - -application { - mainClass = "${project.mainClass}" -} - diff --git a/examples/quickstarts/helidon-quickstart-se/pom.xml b/examples/quickstarts/helidon-quickstart-se/pom.xml deleted file mode 100644 index 2011b6b974c..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/pom.xml +++ /dev/null @@ -1,116 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.quickstarts - helidon-quickstart-se - 4.1.0-SNAPSHOT - Helidon Examples Quickstart SE - - - io.helidon.examples.quickstart.se.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.http.media - helidon-http-media-jsonp - - - io.helidon.webserver.observe - helidon-webserver-observe-health - - - io.helidon.webserver.observe - helidon-webserver-observe-metrics - - - io.helidon.metrics - helidon-metrics-system-meters - - - io.helidon.openapi - helidon-openapi - - - io.helidon.config - helidon-config-yaml - - - io.helidon.health - helidon-health-checks - - - jakarta.json - jakarta.json-api - - - io.helidon.logging - helidon-logging-jul - runtime - - - org.junit.jupiter - junit-jupiter-api - test - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - io.helidon.webclient - helidon-webclient - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/quickstarts/helidon-quickstart-se/settings.gradle b/examples/quickstarts/helidon-quickstart-se/settings.gradle deleted file mode 100644 index e38154975c6..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/settings.gradle +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) 2018, 2021 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. - */ - -rootProject.name = 'helidon-quickstart-se' diff --git a/examples/quickstarts/helidon-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/GreetService.java b/examples/quickstarts/helidon-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/GreetService.java deleted file mode 100644 index 4f098af3d97..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/GreetService.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.quickstart.se; - -import java.util.Collections; -import java.util.concurrent.atomic.AtomicReference; - -import io.helidon.config.Config; -import io.helidon.http.Status; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; - -/** - * A simple service to greet you. Examples: - *

      - * Get default greeting message: - * {@code curl -X GET http://localhost:8080/greet} - *

      - * Get greeting message for Joe: - * {@code curl -X GET http://localhost:8080/greet/Joe} - *

      - * Change greeting - * {@code 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 HttpService { - - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - /** - * The config value for the key {@code greeting}. - */ - private final AtomicReference greeting = new AtomicReference<>(); - - GreetService() { - this(Config.global().get("app")); - } - - GreetService(Config appConfig) { - greeting.set(appConfig.get("greeting").asString().orElse("Ciao")); - } - - /** - * A service registers itself by updating the routing rules. - * - * @param rules the routing rules. - */ - @Override - public void routing(HttpRules 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().pathParameters().get("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 void updateGreetingFromJson(JsonObject jo, ServerResponse response) { - if (!jo.containsKey("greeting")) { - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "No greeting provided") - .build(); - response.status(Status.BAD_REQUEST_400) - .send(jsonErrorObject); - return; - } - - greeting.set(jo.getString("greeting")); - response.status(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) { - updateGreetingFromJson(request.content().as(JsonObject.class), response); - } -} diff --git a/examples/quickstarts/helidon-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/Main.java b/examples/quickstarts/helidon-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/Main.java deleted file mode 100644 index be7544c9a30..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/Main.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.quickstart.se; - -import io.helidon.config.Config; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.http.HttpRouting; - -/** - * 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(String[] args) { - // load logging configuration - LogConfig.configureRuntime(); - - // initialize global config from default configuration - Config config = Config.create(); - Config.global(config); - - WebServer server = WebServer.builder() - .config(config.get("server")) - .routing(Main::routing) - .build() - .start(); - - System.out.println("WEB server is up! http://localhost:" + server.port() + "/greet"); - } - - /** - * Updates HTTP Routing and registers observe providers. - */ - static void routing(HttpRouting.Builder routing) { - routing.register("/greet", new GreetService()); - } -} diff --git a/examples/quickstarts/helidon-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/package-info.java b/examples/quickstarts/helidon-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/package-info.java deleted file mode 100644 index fa1f34d7bd2..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2017, 2021 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. - */ - -/** - * Quickstart demo application - *

      - * Start with {@link io.helidon.examples.quickstart.se.Main} class. - * - * @see io.helidon.examples.quickstart.se.Main - */ -package io.helidon.examples.quickstart.se; diff --git a/examples/quickstarts/helidon-quickstart-se/src/main/resources/application.yaml b/examples/quickstarts/helidon-quickstart-se/src/main/resources/application.yaml deleted file mode 100644 index 03c339ff109..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/src/main/resources/application.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# -# Copyright (c) 2018, 2023 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. -# - -app: - greeting: "Hello" - -server: - port: 8080 - host: 0.0.0.0 - # default behavior to discover Server features (observability, openapi, metrics) - # features-discovers-services: true - # all of the below is discovered automatically - # features: - # observe: - # observers: - # metrics: - # health: - # enabled: false diff --git a/examples/quickstarts/helidon-quickstart-se/src/main/resources/logging.properties b/examples/quickstarts/helidon-quickstart-se/src/main/resources/logging.properties deleted file mode 100644 index 51d343b5df1..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/src/main/resources/logging.properties +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) 2023, 2024 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. -# - -handlers=io.helidon.logging.jul.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS.%1$tL %4$s %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO -io.helidon.level=INFO diff --git a/examples/quickstarts/helidon-quickstart-se/src/test/java/io/helidon/examples/quickstart/se/MainTest.java b/examples/quickstarts/helidon-quickstart-se/src/test/java/io/helidon/examples/quickstart/se/MainTest.java deleted file mode 100644 index 40917691d99..00000000000 --- a/examples/quickstarts/helidon-quickstart-se/src/test/java/io/helidon/examples/quickstart/se/MainTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.quickstart.se; - -import io.helidon.http.Status; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.http.HttpRouting; -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpRoute; - -import jakarta.json.JsonObject; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -@ServerTest -class MainTest { - - private final Http1Client client; - - protected MainTest(Http1Client client) { - this.client = client; - } - - @SetUpRoute - static void routing(HttpRouting.Builder builder) { - Main.routing(builder); - } - - @Test - void testRootRoute() { - try (Http1ClientResponse response = client.get("/greet").request()) { - assertThat(response.status(), is(Status.OK_200)); - JsonObject json = response.as(JsonObject.class); - assertThat(json.getString("message"), is("Hello World!")); - } - } - - @Test - void testHealthObserver() { - try (Http1ClientResponse response = client.get("/observe/health").request()) { - assertThat(response.status(), is(Status.NO_CONTENT_204)); - } - } - - @Test - void testDeadlockHealthCheck() { - try (Http1ClientResponse response = client.get("/observe/health/live/deadlock").request()) { - assertThat(response.status(), is(Status.NO_CONTENT_204)); - } - } - - @Test - void testMetricsObserver() { - try (Http1ClientResponse response = client.get("/observe/metrics").request()) { - assertThat(response.status(), is(Status.OK_200)); - } - } -} diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/.dockerignore b/examples/quickstarts/helidon-standalone-quickstart-mp/.dockerignore deleted file mode 100644 index c8b241f2215..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -target/* \ No newline at end of file diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/.gitignore b/examples/quickstarts/helidon-standalone-quickstart-mp/.gitignore deleted file mode 100644 index 594f3abf63c..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -hs_err_pid* -target/ -.DS_Store -.idea/ -*.iws -*.ipr -*.iml -atlassian-ide-plugin.xml -nbactions.xml -nb-configuration.xml -.settings -.settings/ -.project -.classpath -*.swp -*~ diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile b/examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile deleted file mode 100644 index 5a1cb9c900e..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile +++ /dev/null @@ -1,53 +0,0 @@ -# -# Copyright (c) 2018, 2024 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. -# - -# 1st stage, build the app -FROM container-registry.oracle.com/java/jdk-no-fee-term:21 as build - -# Install maven -WORKDIR /usr/share -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 -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 container-registry.oracle.com/java/jdk-no-fee-term:21 -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/helidon-standalone-quickstart-mp.jar ./ -COPY --from=build /helidon/target/libs ./libs - -CMD ["java", "-jar", "helidon-standalone-quickstart-mp.jar"] - -EXPOSE 8080 diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile.jlink b/examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile.jlink deleted file mode 100644 index a33effbdbaa..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile.jlink +++ /dev/null @@ -1,49 +0,0 @@ -# -# Copyright (c) 2020, 2024 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. -# - -# 1st stage, build the app -FROM container-registry.oracle.com/java/jdk-no-fee-term:21 as build - -# Install maven -WORKDIR /usr/share -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 -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 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/helidon-standalone-quickstart-mp-jri ./ -ENTRYPOINT ["/bin/bash", "/helidon/bin/start"] -EXPOSE 8080 diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile.native b/examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile.native deleted file mode 100644 index ea9b8eb9fb6..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/Dockerfile.native +++ /dev/null @@ -1,54 +0,0 @@ -# -# Copyright (c) 2020, 2023 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. -# - -# 1st stage, build the app -FROM ghcr.io/graalvm/graalvm-community:21.0.0-ol9 as build - -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/helidon-standalone-quickstart-mp . - -ENTRYPOINT ["./helidon-standalone-quickstart-mp"] - -EXPOSE 8080 diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/README.md b/examples/quickstarts/helidon-standalone-quickstart-mp/README.md deleted file mode 100644 index 30297464815..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/README.md +++ /dev/null @@ -1,160 +0,0 @@ -# Helidon Examples Standalone Quickstart MP - -This example implements a simple Hello World REST service using MicroProfile - with a standalone Maven pom. - -## Build and run - -```shell -mvn package -java -jar target/helidon-standalone-quickstart-mp.jar -``` - -## Exercise the application - -```shell -curl -X GET http://localhost:8080/greet -#Output: {"message":"Hello World!"} - -curl -X GET http://localhost:8080/greet/Joe -#Output: {"message":"Hello Joe!"} - -curl -X PUT -H "Content-Type: application/json" -d '{"message" : "Hola"}' http://localhost:8080/greet/greeting - -curl -X GET http://localhost:8080/greet/Jose -#Output: {"message":"Hola Jose!"} -``` - -## Try health and metrics - -```shell -curl -s -X GET http://localhost:8080/health -#Output: {"outcome":"UP",... - -# Prometheus Format -curl -s -X GET http://localhost:8080/metrics -# TYPE base:gc_g1_young_generation_count gauge - -# JSON Format -curl -H 'Accept: application/json' -X GET http://localhost:8080/metrics -#Output: {"base":... -``` - -## Build the Docker Image - -```shell -docker build -t helidon-standalone-quickstart-mp . -``` - -## Start the application with Docker - -```shell -docker run --rm -p 8080:8080 helidon-standalone-quickstart-mp:latest -``` - -Exercise the application as described above - -## Deploy the application to Kubernetes - -```shell -kubectl cluster-info # Verify which cluster -kubectl get pods # Verify connectivity to cluster -kubectl create -f app.yaml # Deploy application -kubectl get service helidon-standalone-quickstart-mp # Verify deployed service -``` - -## Build a native image with GraalVM - -GraalVM allows you to compile your programs ahead-of-time into a native - executable. See https://www.graalvm.org/docs/reference-manual/aot-compilation/ - for more information. - -You can build a native executable in 2 different ways: -* With a local installation of GraalVM -* Using Docker - -### Local build - -Download Graal VM at https://www.graalvm.org/downloads. - -```shell -# Setup the environment -export GRAALVM_HOME=/path -# build the native executable -mvn package -Pnative-image -``` - -You can also put the Graal VM `bin` directory in your PATH, or pass - `-DgraalVMHome=/path` to the Maven command. - -See https://github.com/oracle/helidon-build-tools/tree/master/helidon-maven-plugin#goal-native-image - for more information. - -Start the application: - -```shell -./target/helidon-quickstart-mp -``` - -### Multi-stage Docker build - -Build the "native" Docker Image - -```shell -docker build -t helidon-standalone-quickstart-mp-native -f Dockerfile.native . -``` - -Start the application: - -```shell -docker run --rm -p 8080:8080 helidon-standalone-quickstart-mp-native:latest -``` - -## Build a Java Runtime Image using jlink - -You can build a custom Java Runtime Image (JRI) containing the application jars and the JDK modules -on which they depend. This image also: - -* Enables Class Data Sharing by default to reduce startup time. -* Contains a customized `start` script to simplify CDS usage and support debug and test modes. - -You can build a custom JRI in two different ways: -* Local -* Using Docker - - -### Local build - -```shell -# build the JRI -mvn package -Pjlink-image -``` - -See https://github.com/oracle/helidon-build-tools/tree/master/helidon-maven-plugin#goal-jlink-image - for more information. - -Start the application: - -```shell -./target/helidon-standalone-quickstart-mp-jri/bin/start -``` - -### Multi-stage Docker build - -Build the JRI as a Docker Image - -```shell -docker build -t helidon-standalone-quickstart-mp-jri -f Dockerfile.jlink . -``` - -Start the application: - -```shell -docker run --rm -p 8080:8080 helidon-standalone-quickstart-mp-jri:latest -``` - -See the start script help: - -```shell -docker run --rm helidon-standalone-quickstart-mp-jri:latest --help -``` \ No newline at end of file diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/app.yaml b/examples/quickstarts/helidon-standalone-quickstart-mp/app.yaml deleted file mode 100644 index 7d330579c02..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/app.yaml +++ /dev/null @@ -1,57 +0,0 @@ -# -# Copyright (c) 2018, 2021 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. -# - -kind: Service -apiVersion: v1 -metadata: - name: helidon-quickstart-mp - labels: - app: helidon-quickstart-mp -spec: - type: NodePort - selector: - app: helidon-quickstart-mp - ports: - - port: 8080 - targetPort: 8080 - name: http ---- - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: helidon-quickstart-mp - labels: - app: helidon-quickstart-mp - version: v1 -spec: - replicas: 1 - selector: - matchLabels: - app: helidon-quickstart-mp - version: v1 - template: - metadata: - labels: - app: helidon-quickstart-mp - version: v1 - spec: - containers: - - name: helidon-quickstart-mp - image: helidon-quickstart-mp - imagePullPolicy: IfNotPresent - ports: - - containerPort: 8080 diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/pom.xml b/examples/quickstarts/helidon-standalone-quickstart-mp/pom.xml deleted file mode 100644 index bb9060a27ea..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/pom.xml +++ /dev/null @@ -1,317 +0,0 @@ - - - - 4.0.0 - io.helidon.examples.quickstarts - helidon-standalone-quickstart-mp - 4.1.0-SNAPSHOT - Helidon Examples Standalone Quickstart MP - - - 4.1.0-SNAPSHOT - io.helidon.microprofile.cdi.Main - - 21 - ${maven.compiler.source} - true - UTF-8 - UTF-8 - - - 3.8.1 - 3.6.0 - 2.7.5.1 - 1.6.0 - 3.0.0-M5 - 4.0.9 - 4.0.9 - 3.1.2 - 3.0.2 - 0.10.2 - 1.5.0.Final - 0.5.1 - 2.7 - 3.0.0-M5 - - - - - - io.helidon - helidon-dependencies - ${helidon.version} - pom - import - - - - - - - io.helidon.microprofile.bundles - helidon-microprofile-core - - - io.helidon.microprofile.openapi - helidon-microprofile-openapi - - - io.helidon.microprofile.health - helidon-microprofile-health - - - io.helidon.microprofile.metrics - helidon-microprofile-metrics - - - io.helidon.logging - helidon-logging-jul - runtime - - - jakarta.json.bind - jakarta.json.bind-api - - - org.glassfish.jersey.media - jersey-media-json-binding - runtime - - - io.smallrye - jandex - runtime - true - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.microprofile.testing - helidon-microprofile-testing-junit5 - test - - - - - ${project.artifactId} - - - - org.apache.maven.plugins - maven-compiler-plugin - ${version.plugin.compiler} - - - org.apache.maven.plugins - maven-surefire-plugin - ${version.plugin.surefire} - - false - - ${project.build.outputDirectory}/logging.properties - - - - - org.apache.maven.plugins - maven-failsafe-plugin - ${version.plugin.failsafe} - - false - true - - - - org.apache.maven.plugins - maven-dependency-plugin - ${version.plugin.dependency} - - - org.apache.maven.plugins - maven-resources-plugin - ${version.plugin.resources} - - - org.apache.maven.plugins - maven-jar-plugin - ${version.plugin.jar} - - - - true - libs - ${mainClass} - false - - - - - - io.smallrye - jandex-maven-plugin - ${version.plugin.jandex} - - - org.codehaus.mojo - exec-maven-plugin - ${version.plugin.exec} - - ${mainClass} - - - - io.helidon.build-tools - helidon-maven-plugin - ${version.plugin.helidon} - - - io.helidon.build-tools - helidon-cli-maven-plugin - ${version.plugin.helidon-cli} - - - org.graalvm.buildtools - native-maven-plugin - ${version.plugin.nativeimage} - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - prepare-package - - copy-dependencies - - - ${project.build.directory}/libs - false - false - true - true - runtime - - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - jandex - - process-classes - - - - - - - - - native-image - - - - org.graalvm.buildtools - native-maven-plugin - ${version.plugin.nativeimage} - - - resource-config - package - - generateResourceConfig - - - - true - - - - build-native-image - package - - compile-no-fork - - - - true - - ${project.build.outputDirectory} - ${project.build.finalName} - false - - false - - - - --add-exports=org.graalvm.nativeimage.builder/com.oracle.svm.core.configure=ALL-UNNAMED - - - - - - - - - - io.helidon.integrations.graal - helidon-mp-graal-native-image-extension - - - - - jlink-image - - - - io.helidon.build-tools - helidon-maven-plugin - - - - jlink-image - - - - - - - - - diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetResource.java b/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetResource.java deleted file mode 100644 index 5de0bde8832..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetResource.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.quickstart.mp; - -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 GreetingMessage} - */ - @GET - @Produces(MediaType.APPLICATION_JSON) - public GreetingMessage getDefaultMessage() { - return createResponse("World"); - } - - /** - * Return a greeting message using the name that was provided. - * - * @param name the name to greet - * @return {@link GreetingMessage} - */ - @Path("/{name}") - @GET - @Produces(MediaType.APPLICATION_JSON) - public GreetingMessage getMessage(@PathParam("name") String name) { - return createResponse(name); - } - - /** - * Set the greeting to use in future messages. - * - * @param message 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(GreetingMessage message) { - if (message.getMessage() == null) { - GreetingMessage entity = new GreetingMessage("No greeting provided"); - return Response.status(Response.Status.BAD_REQUEST).entity(entity).build(); - } - - greetingProvider.setMessage(message.getMessage()); - return Response.status(Response.Status.NO_CONTENT).build(); - } - - private GreetingMessage createResponse(String who) { - String msg = String.format("%s %s!", greetingProvider.getMessage(), who); - - return new GreetingMessage(msg); - } -} diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingMessage.java b/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingMessage.java deleted file mode 100644 index eab1bac7963..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingMessage.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2023 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.quickstart.mp; - -/** - * POJO defining the greeting message content. - */ -@SuppressWarnings("unused") -public class GreetingMessage { - private String message; - - /** - * Create a new GreetingMessage instance. - */ - public GreetingMessage() { - } - - /** - * Create a new GreetingMessage instance. - * - * @param message message - */ - public GreetingMessage(String message) { - this.message = message; - } - - /** - * Gets the message value. - * - * @return message value - */ - public String getMessage() { - return message; - } - - /** - * Sets the message value. - * - * @param message message value to set - */ - public void setMessage(String message) { - this.message = message; - } -} diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingProvider.java b/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingProvider.java deleted file mode 100644 index ab2c02af499..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/GreetingProvider.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2019, 2021 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.quickstart.mp; - -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/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/package-info.java b/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/package-info.java deleted file mode 100644 index ca190d47ecf..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/java/io/helidon/examples/quickstart/mp/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2019, 2021 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. - */ - -/** - * Quickstart MicroProfile example. - */ -package io.helidon.examples.quickstart.mp; diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/resources/META-INF/beans.xml b/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/resources/META-INF/beans.xml deleted file mode 100644 index f2f827007a8..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/resources/META-INF/microprofile-config.properties b/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/resources/META-INF/microprofile-config.properties deleted file mode 100644 index c2246f264ca..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/resources/META-INF/microprofile-config.properties +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2019, 2020 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. -# - -# Application properties. This is the default greeting -app.greeting=Hello - -# Microprofile server properties -server.port=8080 -server.host=0.0.0.0 - -# Enable the optional MicroProfile Metrics REST.request metrics -metrics.rest-request.enabled=true diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/resources/META-INF/native-image/io.helidon.examples.quickstarts/helidon-standalone-quickstart-mp/native-image.properties b/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/resources/META-INF/native-image/io.helidon.examples.quickstarts/helidon-standalone-quickstart-mp/native-image.properties deleted file mode 100644 index bac3f92ae57..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/resources/META-INF/native-image/io.helidon.examples.quickstarts/helidon-standalone-quickstart-mp/native-image.properties +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2023 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. -# - -Args=--initialize-at-build-time=io.helidon.examples diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/resources/logging.properties b/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/resources/logging.properties deleted file mode 100644 index 7b395f50eb6..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/src/main/resources/logging.properties +++ /dev/null @@ -1,38 +0,0 @@ -# -# Copyright (c) 2018, 2024 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 - -## Send messages to the console -handlers=io.helidon.logging.jul.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.microprofile.level=INFO -#io.helidon.common.level=INFO -#org.jboss.weld=INFO diff --git a/examples/quickstarts/helidon-standalone-quickstart-mp/src/test/java/io/helidon/examples/quickstart/mp/MainTest.java b/examples/quickstarts/helidon-standalone-quickstart-mp/src/test/java/io/helidon/examples/quickstart/mp/MainTest.java deleted file mode 100644 index 3a63a072d7c..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-mp/src/test/java/io/helidon/examples/quickstart/mp/MainTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.quickstart.mp; - -import io.helidon.microprofile.testing.junit5.HelidonTest; - -import jakarta.inject.Inject; -import jakarta.ws.rs.client.Entity; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -@HelidonTest -class MainTest { - private final WebTarget target; - - @Inject - MainTest(WebTarget target) { - this.target = target; - } - - @Test - void testHelloWorld() { - - GreetingMessage message = target.path("/greet") - .request() - .get(GreetingMessage.class); - assertThat("default message", message.getMessage(), - is("Hello World!")); - - message = target.path("/greet/Joe") - .request() - .get(GreetingMessage.class); - assertThat("hello Joe message", message.getMessage(), - is("Hello Joe!")); - - try (Response r = target.path("/greet/greeting") - .request() - .put(Entity.entity("{\"message\" : \"Hola\"}", MediaType.APPLICATION_JSON))) { - assertThat("PUT status code", r.getStatus(), is(204)); - } - - message = target.path("/greet/Jose") - .request() - .get(GreetingMessage.class); - assertThat("hola Jose message", message.getMessage(), - is("Hola Jose!")); - - try (Response r = target.path("/metrics") - .request() - .get()) { - assertThat("GET metrics status code", r.getStatus(), is(200)); - } - - try (Response r = target.path("/health") - .request() - .get()) { - assertThat("GET health status code", r.getStatus(), is(200)); - } - } -} diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/.dockerignore b/examples/quickstarts/helidon-standalone-quickstart-se/.dockerignore deleted file mode 100644 index c8b241f2215..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -target/* \ No newline at end of file diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/.gitignore b/examples/quickstarts/helidon-standalone-quickstart-se/.gitignore deleted file mode 100644 index 241e8042d94..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -hs_err_pid* -target/ -.DS_Store -.idea/ -*.iws -*.ipr -*.iml -atlassian-ide-plugin.xml -nbactions.xml -nb-configuration.xml -.settings -.settings/ -.project -.classpath -*.swp -*~ \ No newline at end of file diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile b/examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile deleted file mode 100644 index 6a484e96ee7..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile +++ /dev/null @@ -1,54 +0,0 @@ -# -# Copyright (c) 2018, 2024 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. -# - -# 1st stage, build the app -FROM container-registry.oracle.com/java/jdk-no-fee-term:21 as build - -# Install maven -WORKDIR /usr/share -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 -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 container-registry.oracle.com/java/jdk-no-fee-term:21 -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/helidon-standalone-quickstart-se.jar ./ -COPY --from=build /helidon/target/libs ./libs - -CMD ["java", "-jar", "helidon-standalone-quickstart-se.jar"] - -EXPOSE 8080 diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile.jlink b/examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile.jlink deleted file mode 100644 index 61979ba2f21..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile.jlink +++ /dev/null @@ -1,49 +0,0 @@ -# -# Copyright (c) 2020, 2024 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. -# - -# 1st stage, build the app -FROM container-registry.oracle.com/java/jdk-no-fee-term:21 as build - -# Install maven -WORKDIR /usr/share -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 -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 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/helidon-standalone-quickstart-se-jri ./ -ENTRYPOINT ["/bin/bash", "/helidon/bin/start"] -EXPOSE 8080 diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile.native b/examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile.native deleted file mode 100644 index 7c4461c0d40..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/Dockerfile.native +++ /dev/null @@ -1,54 +0,0 @@ -# -# Copyright (c) 2019, 2023 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. -# - -# 1st stage, build the app -FROM ghcr.io/graalvm/graalvm-community:21.0.0-ol9 as build - -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/helidon-standalone-quickstart-se . - -ENTRYPOINT ["./helidon-standalone-quickstart-se"] - -EXPOSE 8080 diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/README.md b/examples/quickstarts/helidon-standalone-quickstart-se/README.md deleted file mode 100644 index 8b1fdc1104a..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/README.md +++ /dev/null @@ -1,161 +0,0 @@ -# Helidon Examples Standalone Quickstart SE - -This project implements a simple Hello World REST service using Helidon SE with - a standalone Maven pom. - -## Build and run - -```shell -mvn package -java -jar target/helidon-standalone-quickstart-se.jar -``` - -## Exercise the application - -```shell -curl -X GET http://localhost:8080/greet -#Output: {"message":"Hello World!"} - -curl -X GET http://localhost:8080/greet/Joe -#Output: {"message":"Hello Joe!"} - -curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}' http://localhost:8080/greet/greeting - -curl -X GET http://localhost:8080/greet/Jose -#Output: {"message":"Hola Jose!"} -``` - -## Try health and metrics - -```shell -curl -s -X GET http://localhost:8080/observe/health -#Output: {"outcome":"UP",... - -# Prometheus Format -curl -s -X GET http://localhost:8080/observe/metrics -# TYPE base:gc_g1_young_generation_count gauge - -# JSON Format -curl -H 'Accept: application/json' -X GET http://localhost:8080/observe/metrics -#Output: {"base":... -``` - -## Build the Docker Image - -```shell -docker build -t helidon-standalone-quickstart-se . -``` - -## Start the application with Docker - -```shell -docker run --rm -p 8080:8080 helidon-standalone-quickstart-se:latest -``` - -Exercise the application as described above - -## Deploy the application to Kubernetes - -```shell -kubectl cluster-info # Verify which cluster -kubectl get pods # Verify connectivity to cluster -kubectl create -f app.yaml # Deply application -kubectl get service helidon-standalone-quickstart-se # Get service info -``` - -## Build a native image with GraalVM - -GraalVM allows you to compile your programs ahead-of-time into a native - executable. See https://www.graalvm.org/docs/reference-manual/aot-compilation/ - for more information. - -You can build a native executable in 2 different ways: -* With a local installation of GraalVM -* Using Docker - -### Local build - -Download Graal VM at https://www.graalvm.org/downloads. We recommend -version `23.1.0` or later. - -```shell -# Setup the environment -export GRAALVM_HOME=/path -# build the native executable -mvn package -Pnative-image -``` - -You can also put the Graal VM `bin` directory in your PATH, or pass - `-DgraalVMHome=/path` to the Maven command. - -See https://github.com/oracle/helidon-build-tools/tree/master/helidon-maven-plugin - for more information. - -Start the application: - -```shell -./target/helidon-standalone-quickstart-se -``` - -### Multi-stage Docker build - -Build the "native" Docker Image - -```shell -docker build -t helidon-standalone-quickstart-se-native -f Dockerfile.native . -``` - -Start the application: - -```shell -docker run --rm -p 8080:8080 helidon-standalone-quickstart-se-native:latest -``` - -## Build a Java Runtime Image using jlink - -You can build a custom Java Runtime Image (JRI) containing the application jars and the JDK modules -on which they depend. This image also: - -* Enables Class Data Sharing by default to reduce startup time. -* Contains a customized `start` script to simplify CDS usage and support debug and test modes. - -You can build a custom JRI in two different ways: -* Local -* Using Docker - - -### Local build - -```shell -# build the JRI -mvn package -Pjlink-image -``` - -See https://github.com/oracle/helidon-build-tools/tree/master/helidon-maven-plugin#goal-jlink-image - for more information. - -Start the application: - -```shell -./target/helidon-standalone-quickstart-se-jri/bin/start -``` - -### Multi-stage Docker build - -Build the JRI as a Docker Image - -```shell -docker build -t helidon-standalone-quickstart-se-jri -f Dockerfile.jlink . -``` - -Start the application: - -```shell -docker run --rm -p 8080:8080 helidon-standalone-quickstart-se-jri:latest -``` - -See the start script help: - -```shell -docker run --rm helidon-standalone-quickstart-se-jri:latest --help -``` \ No newline at end of file diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/app.yaml b/examples/quickstarts/helidon-standalone-quickstart-se/app.yaml deleted file mode 100644 index 00fdab888f6..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/app.yaml +++ /dev/null @@ -1,57 +0,0 @@ -# -# Copyright (c) 2018, 2021 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. -# - -kind: Service -apiVersion: v1 -metadata: - name: helidon-quickstart-se - labels: - app: helidon-quickstart-se -spec: - type: NodePort - selector: - app: helidon-quickstart-se - ports: - - port: 8080 - targetPort: 8080 - name: http ---- - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: helidon-quickstart-se - labels: - app: helidon-quickstart-se - version: v1 -spec: - replicas: 1 - selector: - matchLabels: - app: helidon-quickstart-se - version: v1 - template: - metadata: - labels: - app: helidon-quickstart-se - version: v1 - spec: - containers: - - name: helidon-quickstart-se - image: helidon-quickstart-se - imagePullPolicy: IfNotPresent - ports: - - containerPort: 8080 diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/pom.xml b/examples/quickstarts/helidon-standalone-quickstart-se/pom.xml deleted file mode 100644 index b6b31c4ce54..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/pom.xml +++ /dev/null @@ -1,307 +0,0 @@ - - - - - 4.0.0 - io.helidon.examples.quickstarts - helidon-standalone-quickstart-se - 4.1.0-SNAPSHOT - Helidon Examples Standalone Quickstart SE - - - 4.1.0-SNAPSHOT - test - io.helidon.examples.quickstart.se.Main - - 21 - ${maven.compiler.source} - true - UTF-8 - UTF-8 - - - 3.8.1 - 3.6.0 - 1.6.0 - 3.0.0-M5 - 4.0.9 - 4.0.9 - 3.0.2 - 0.10.2 - 1.5.0.Final - 0.5.1 - 2.7 - 3.0.0-M5 - - - - - - io.helidon - helidon-dependencies - ${helidon.version} - pom - import - - - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.http.media - helidon-http-media-jsonp - - - io.helidon.webserver.observe - helidon-webserver-observe-health - - - io.helidon.webserver.observe - helidon-webserver-observe-metrics - runtime - - - io.helidon.metrics - helidon-metrics-system-meters - runtime - - - io.helidon.openapi - helidon-openapi - - - io.helidon.config - helidon-config-yaml - - - io.helidon.health - helidon-health-checks - - - jakarta.json - jakarta.json-api - - - org.junit.jupiter - junit-jupiter-api - test - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - io.helidon.webclient - helidon-webclient - test - - - org.hamcrest - hamcrest-all - test - - - - - ${project.artifactId} - - - - org.apache.maven.plugins - maven-compiler-plugin - ${version.plugin.compiler} - - - org.apache.maven.plugins - maven-surefire-plugin - ${version.plugin.surefire} - - false - - ${project.build.outputDirectory}/logging.properties - ${helidon.test.config.profile} - - - - - org.apache.maven.plugins - maven-failsafe-plugin - ${version.plugin.failsafe} - - false - true - - - - org.apache.maven.plugins - maven-dependency-plugin - ${version.plugin.dependency} - - - org.apache.maven.plugins - maven-resources-plugin - ${version.plugin.resources} - - - org.apache.maven.plugins - maven-jar-plugin - ${version.plugin.jar} - - - - true - libs - ${mainClass} - false - - - - - - org.codehaus.mojo - exec-maven-plugin - ${version.plugin.exec} - - ${mainClass} - - - - io.helidon.build-tools - helidon-maven-plugin - ${version.plugin.helidon} - - - io.helidon.build-tools - helidon-cli-maven-plugin - ${version.plugin.helidon-cli} - - - org.graalvm.buildtools - native-maven-plugin - ${version.plugin.nativeimage} - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - prepare-package - - copy-dependencies - - - ${project.build.directory}/libs - false - false - true - true - runtime - - - - - - - - - - native-image - - - - org.graalvm.buildtools - native-maven-plugin - ${version.plugin.nativeimage} - - - resource-config - package - - generateResourceConfig - - - - true - - - - build-native-image - package - - compile-no-fork - - - - true - - ${project.build.outputDirectory} - ${project.build.finalName} - false - - false - - - - --add-exports=org.graalvm.nativeimage.builder/com.oracle.svm.core.configure=ALL-UNNAMED - - - - - - - - - - io.helidon.integrations.graal - helidon-graal-native-image-extension - - - - - jlink-image - - - - io.helidon.build-tools - helidon-maven-plugin - - - - jlink-image - - - - - - - - - diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/GreetService.java b/examples/quickstarts/helidon-standalone-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/GreetService.java deleted file mode 100644 index 4f098af3d97..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/GreetService.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.quickstart.se; - -import java.util.Collections; -import java.util.concurrent.atomic.AtomicReference; - -import io.helidon.config.Config; -import io.helidon.http.Status; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; - -/** - * A simple service to greet you. Examples: - *

      - * Get default greeting message: - * {@code curl -X GET http://localhost:8080/greet} - *

      - * Get greeting message for Joe: - * {@code curl -X GET http://localhost:8080/greet/Joe} - *

      - * Change greeting - * {@code 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 HttpService { - - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - /** - * The config value for the key {@code greeting}. - */ - private final AtomicReference greeting = new AtomicReference<>(); - - GreetService() { - this(Config.global().get("app")); - } - - GreetService(Config appConfig) { - greeting.set(appConfig.get("greeting").asString().orElse("Ciao")); - } - - /** - * A service registers itself by updating the routing rules. - * - * @param rules the routing rules. - */ - @Override - public void routing(HttpRules 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().pathParameters().get("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 void updateGreetingFromJson(JsonObject jo, ServerResponse response) { - if (!jo.containsKey("greeting")) { - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "No greeting provided") - .build(); - response.status(Status.BAD_REQUEST_400) - .send(jsonErrorObject); - return; - } - - greeting.set(jo.getString("greeting")); - response.status(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) { - updateGreetingFromJson(request.content().as(JsonObject.class), response); - } -} diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/Main.java b/examples/quickstarts/helidon-standalone-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/Main.java deleted file mode 100644 index a032cb43064..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/Main.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.quickstart.se; - -import io.helidon.config.Config; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.http.HttpRouting; - -/** - * 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(String[] args) { - // load logging configuration - LogConfig.configureRuntime(); - - // initialize global config from default configuration - Config config = Config.create(); - Config.global(config); - - WebServer server = WebServer.builder() - .config(config.get("server")) - .routing(Main::routing) - .build() - .start(); - - System.out.println("WEB server is up! http://localhost:" + server.port() + "/greet"); - } - - /** - * Updates HTTP Routing and registers observe providers. - */ - static void routing(HttpRouting.Builder routing) { - Config config = Config.global(); - - routing.register("/greet", new GreetService()); - } -} diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/package-info.java b/examples/quickstarts/helidon-standalone-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/package-info.java deleted file mode 100644 index 82f9c8de205..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/java/io/helidon/examples/quickstart/se/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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. - */ - -/** - * Quickstart demo application - *

      - * Start with {@link io.helidon.examples.quickstart.se.Main} class. - * - * @see io.helidon.examples.quickstart.se.Main - */ -package io.helidon.examples.quickstart.se; diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/META-INF/native-image/io.helidon.examples.quickstarts/helidon-standalone-quickstart-se/helidon-example-reflection-config.json b/examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/META-INF/native-image/io.helidon.examples.quickstarts/helidon-standalone-quickstart-se/helidon-example-reflection-config.json deleted file mode 100644 index fe51488c706..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/META-INF/native-image/io.helidon.examples.quickstarts/helidon-standalone-quickstart-se/helidon-example-reflection-config.json +++ /dev/null @@ -1 +0,0 @@ -[] diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/META-INF/native-image/io.helidon.examples.quickstarts/helidon-standalone-quickstart-se/native-image.properties b/examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/META-INF/native-image/io.helidon.examples.quickstarts/helidon-standalone-quickstart-se/native-image.properties deleted file mode 100644 index cfcdd39853f..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/META-INF/native-image/io.helidon.examples.quickstarts/helidon-standalone-quickstart-se/native-image.properties +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2019, 2024 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. -# - -Args=-H:ReflectionConfigurationResources=${.}/helidon-example-reflection-config.json diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/application.yaml b/examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/application.yaml deleted file mode 100644 index e90f07e2e00..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/application.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) 2018, 2023 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. -# - -app: - greeting: "Hello" - -server: - port: 8080 - host: 0.0.0.0 diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/logging.properties b/examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/logging.properties deleted file mode 100644 index 175767778e7..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/src/main/resources/logging.properties +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) 2023 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. -# - -handlers=java.util.logging.ConsoleHandler -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS.%1$tL %5$s%6$s%n - -# Global logging level. Can be overridden by specific loggers -.level=INFO -io.helidon.level=INFO diff --git a/examples/quickstarts/helidon-standalone-quickstart-se/src/test/java/io/helidon/examples/quickstart/se/MainTest.java b/examples/quickstarts/helidon-standalone-quickstart-se/src/test/java/io/helidon/examples/quickstart/se/MainTest.java deleted file mode 100644 index eeb59c84537..00000000000 --- a/examples/quickstarts/helidon-standalone-quickstart-se/src/test/java/io/helidon/examples/quickstart/se/MainTest.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.quickstart.se; - -import io.helidon.http.Status; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.http.HttpRouting; -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpRoute; - -import jakarta.json.JsonObject; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -@ServerTest -class MainTest { - - private final Http1Client client; - - protected MainTest(Http1Client client) { - this.client = client; - } - - @SetUpRoute - static void routing(HttpRouting.Builder builder) { - Main.routing(builder); - } - - @Test - void testRootRoute() { - try (Http1ClientResponse response = client.get("/greet").request()) { - assertThat(response.status(), is(Status.OK_200)); - JsonObject json = response.as(JsonObject.class); - assertThat(json.getString("message"), is("Hello World!")); - } - } - - @Test - void testHealthObserver() { - try (Http1ClientResponse response = client.get("/observe/health").request()) { - assertThat(response.status(), is(Status.NO_CONTENT_204)); - } - } - @Test - void testDeadlockHealthCheck() { - try (Http1ClientResponse response = client.get("/observe/health/live/deadlock").request()) { - assertThat(response.status(), is(Status.NO_CONTENT_204)); - } - } - - @Test - void testMetricsObserver() { - try (Http1ClientResponse response = client.get("/observe/metrics").request()) { - assertThat(response.status(), is(Status.OK_200)); - } - } -} diff --git a/examples/quickstarts/pom.xml b/examples/quickstarts/pom.xml deleted file mode 100644 index 662f8b0c0c0..00000000000 --- a/examples/quickstarts/pom.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - 4.0.0 - - io.helidon.examples - helidon-examples-project - 4.1.0-SNAPSHOT - - io.helidon.examples.quickstarts - examples-quickstarts-project - Helidon Examples Quickstart - pom - - - helidon-quickstart-se - helidon-quickstart-mp - helidon-standalone-quickstart-mp - helidon-standalone-quickstart-se - - diff --git a/examples/security/README.md b/examples/security/README.md deleted file mode 100644 index e6b14226b7b..00000000000 --- a/examples/security/README.md +++ /dev/null @@ -1,4 +0,0 @@ - -# Helidon SE Security Examples - - diff --git a/examples/security/attribute-based-access-control/README.md b/examples/security/attribute-based-access-control/README.md deleted file mode 100644 index 972cb44e0d6..00000000000 --- a/examples/security/attribute-based-access-control/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# Helidon Security ABAC Example - -JAX-RS (Jersey) example for attribute based access control. - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-security-abac.jar -``` - -Open endpoints listen in the server's output in a browser. diff --git a/examples/security/attribute-based-access-control/pom.xml b/examples/security/attribute-based-access-control/pom.xml deleted file mode 100644 index 71b7e1b886e..00000000000 --- a/examples/security/attribute-based-access-control/pom.xml +++ /dev/null @@ -1,90 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.security - helidon-examples-security-abac - Helidon Examples Security ABAC - - - Example of attribute based access control. - - - - io.helidon.examples.security.abac.AbacJerseyMain - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.helidon.security.abac - helidon-security-abac-policy-el - - - org.glassfish - jakarta.el - - - io.smallrye - jandex - runtime - true - - - org.junit.jupiter - junit-jupiter-api - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/security/attribute-based-access-control/src/main/java/io/helidon/examples/security/abac/AbacApplication.java b/examples/security/attribute-based-access-control/src/main/java/io/helidon/examples/security/abac/AbacApplication.java deleted file mode 100644 index 69e7ab95b28..00000000000 --- a/examples/security/attribute-based-access-control/src/main/java/io/helidon/examples/security/abac/AbacApplication.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.security.abac; - -import java.util.Set; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.ws.rs.ApplicationPath; -import jakarta.ws.rs.core.Application; - -/** - * Application class of this MP application. - */ -@ApplicationScoped -@ApplicationPath("/rest") -public class AbacApplication extends Application { - @Override - public Set> getClasses() { - return Set.of(AbacResource.class, AbacExplicitResource.class); - } -} diff --git a/examples/security/attribute-based-access-control/src/main/java/io/helidon/examples/security/abac/AbacExplicitResource.java b/examples/security/attribute-based-access-control/src/main/java/io/helidon/examples/security/abac/AbacExplicitResource.java deleted file mode 100644 index 313d2c32934..00000000000 --- a/examples/security/attribute-based-access-control/src/main/java/io/helidon/examples/security/abac/AbacExplicitResource.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.security.abac; - -import java.time.DayOfWeek; - -import io.helidon.security.AuthorizationResponse; -import io.helidon.security.SecurityContext; -import io.helidon.security.SubjectType; -import io.helidon.security.abac.policy.PolicyValidator; -import io.helidon.security.abac.scope.ScopeValidator; -import io.helidon.security.abac.time.TimeValidator; -import io.helidon.security.annotations.Authenticated; -import io.helidon.security.annotations.Authorized; - -import jakarta.json.JsonString; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.core.Context; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; - -/** - * Explicit authorization resource - authorization must be called by programmer. - */ -@Path("/explicit") -@TimeValidator.TimeOfDay(from = "08:15:00", to = "12:00:00") -@TimeValidator.TimeOfDay(from = "12:30:00", to = "17:30:00") -@TimeValidator.DaysOfWeek({DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY, DayOfWeek.FRIDAY}) -@ScopeValidator.Scope("calendar_read") -@ScopeValidator.Scope("calendar_edit") -@PolicyValidator.PolicyStatement("${env.time.year >= 2017 && object.owner == subject.principal.id}") -@Authenticated -public class AbacExplicitResource { - /** - * A resource method to demonstrate explicit authorization. - * - * @param context security context (injected) - * @return "fine, sir" string; or a description of authorization failure - */ - @GET - @Authorized(explicit = true) - @AtnProvider.Authentication(value = "user", - roles = {"user_role"}, - scopes = {"calendar_read", "calendar_edit"}) - @AtnProvider.Authentication(value = "service", - type = SubjectType.SERVICE, - roles = {"service_role"}, - scopes = {"calendar_read", "calendar_edit"}) - public Response process(@Context SecurityContext context) { - SomeResource res = new SomeResource("user"); - AuthorizationResponse atzResponse = context.authorize(res); - - if (atzResponse.isPermitted()) { - //do the update - return Response.ok().entity("fine, sir").build(); - } else { - return Response.status(Response.Status.FORBIDDEN) - .entity(atzResponse.description().orElse("Access not granted")) - .build(); - } - } - - /** - * A resource method to demonstrate explicit authorization - this should fail, as we do not call authorization. - * - * @param context security context (injected) - * @param object a JSON string - * @return "fine, sir" string; or a description of authorization failure - */ - @POST - @Path("/deny") - @Authorized(explicit = true) - @AtnProvider.Authentication(value = "user", - roles = {"user_role"}, - scopes = {"calendar_read", "calendar_edit"}) - @AtnProvider.Authentication(value = "service", - type = SubjectType.SERVICE, - roles = {"service_role"}, - scopes = {"calendar_read", "calendar_edit"}) - @Consumes(MediaType.APPLICATION_JSON) - public Response fail(@Context SecurityContext context, JsonString object) { - return Response.ok("This should not work").build(); - } - - /** - * Example resource. - */ - public static class SomeResource { - private String id; - private String owner; - private String message; - - private SomeResource(String owner) { - this.id = "id"; - this.owner = owner; - this.message = "Unit test"; - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getOwner() { - return owner; - } - - public void setOwner(String owner) { - this.owner = owner; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - } -} diff --git a/examples/security/attribute-based-access-control/src/main/java/io/helidon/examples/security/abac/AbacJerseyMain.java b/examples/security/attribute-based-access-control/src/main/java/io/helidon/examples/security/abac/AbacJerseyMain.java deleted file mode 100644 index b1d9aa7ba09..00000000000 --- a/examples/security/attribute-based-access-control/src/main/java/io/helidon/examples/security/abac/AbacJerseyMain.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.security.abac; - -import io.helidon.config.Config; -import io.helidon.microprofile.server.Server; - -/** - * Jersey example for Attribute based access control. - */ -public final class AbacJerseyMain { - private static Server server; - - private AbacJerseyMain() { - } - - /** - * Main method of example. No arguments required, no configuration required. - * - * @param args empty is OK - * @throws Throwable if server fails to start - */ - public static void main(String[] args) throws Throwable { - server = startIt(); - } - - static Server startIt() { - Config config = Config.create(); - - Server server = Server.builder() - .config(config) - .port(8080) - .build() - .start(); - - System.out.printf("Started server on localhost:%d%n", server.port()); - System.out.println(); - System.out.println("***********************"); - System.out.println("** Endpoints: **"); - System.out.println("***********************"); - System.out.println("Using declarative authorization (ABAC):"); - System.out.printf(" http://localhost:%1$d/rest/attributes%n", server.port()); - System.out.println("Using explicit authorization (ABAC):"); - System.out.printf(" http://localhost:%1$d/rest/explicit%n", server.port()); - - return server; - } -} diff --git a/examples/security/attribute-based-access-control/src/main/java/io/helidon/examples/security/abac/AbacResource.java b/examples/security/attribute-based-access-control/src/main/java/io/helidon/examples/security/abac/AbacResource.java deleted file mode 100644 index 50bc7dbf97e..00000000000 --- a/examples/security/attribute-based-access-control/src/main/java/io/helidon/examples/security/abac/AbacResource.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.security.abac; - -import java.time.DayOfWeek; - -import io.helidon.security.SubjectType; -import io.helidon.security.abac.policy.PolicyValidator; -import io.helidon.security.abac.role.RoleValidator; -import io.helidon.security.abac.scope.ScopeValidator; -import io.helidon.security.abac.time.TimeValidator; -import io.helidon.security.annotations.Authenticated; - -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; - -/** - * Annotation only resource. - */ -@Path("/attributes") -@TimeValidator.TimeOfDay(from = "08:15:00", to = "12:00:00") -@TimeValidator.TimeOfDay(from = "12:30:00", to = "17:30:00") -@TimeValidator.DaysOfWeek({DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY, DayOfWeek.FRIDAY}) -@ScopeValidator.Scope("calendar_read") -@ScopeValidator.Scope("calendar_edit") -@RoleValidator.Roles("user_role") -@RoleValidator.Roles(value = "service_role", subjectType = SubjectType.SERVICE) -@PolicyValidator.PolicyStatement("${env.time.year >= 2017}") -@Authenticated -public class AbacResource { - /** - * A resource method to demonstrate if access was successful or not. - * - * @return "hello" - */ - @GET - @AtnProvider.Authentication(value = "user", - roles = {"user_role"}, - scopes = {"calendar_read", "calendar_edit"}) - @AtnProvider.Authentication(value = "service", - type = SubjectType.SERVICE, - roles = {"service_role"}, - scopes = {"calendar_read", "calendar_edit"}) - public String process() { - return "hello"; - } - - /** - * A resource method to demonstrate if access was successful or not. - * - * @return "hello" - */ - @GET - @Path("/deny") - @PolicyValidator.PolicyStatement("${env.time.year < 2017}") - @AtnProvider.Authentication(value = "user", scopes = {"calendar_read"}) - @AtnProvider.Authentication(value = "service", - type = SubjectType.SERVICE, - roles = {"service_role"}, - scopes = {"calendar_read", "calendar_edit"}) - public String deny() { - return "hello"; - } -} diff --git a/examples/security/attribute-based-access-control/src/main/java/io/helidon/examples/security/abac/AtnProvider.java b/examples/security/attribute-based-access-control/src/main/java/io/helidon/examples/security/abac/AtnProvider.java deleted file mode 100644 index bd3a34df0f6..00000000000 --- a/examples/security/attribute-based-access-control/src/main/java/io/helidon/examples/security/abac/AtnProvider.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.security.abac; - -import java.lang.annotation.Annotation; -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Repeatable; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.util.Arrays; -import java.util.Collection; -import java.util.LinkedList; -import java.util.List; -import java.util.ListIterator; -import java.util.Set; - -import io.helidon.security.AuthenticationResponse; -import io.helidon.security.EndpointConfig; -import io.helidon.security.Grant; -import io.helidon.security.Principal; -import io.helidon.security.ProviderRequest; -import io.helidon.security.Role; -import io.helidon.security.SecurityLevel; -import io.helidon.security.Subject; -import io.helidon.security.SubjectType; -import io.helidon.security.spi.AuthenticationProvider; - -/** - * Example authentication provider that reads annotation to create a subject. - */ -public class AtnProvider implements AuthenticationProvider { - @Override - public AuthenticationResponse authenticate(ProviderRequest providerRequest) { - List securityLevels = providerRequest.endpointConfig().securityLevels(); - ListIterator listIterator = securityLevels.listIterator(securityLevels.size()); - Subject user = null; - Subject service = null; - while (listIterator.hasPrevious()) { - SecurityLevel securityLevel = listIterator.previous(); - List authenticationAnnots = securityLevel - .filterAnnotations(Authentications.class, EndpointConfig.AnnotationScope.METHOD); - - List authentications = new LinkedList<>(); - authenticationAnnots.forEach(atn -> authentications.addAll(Arrays.asList(atn.value()))); - - - if (!authentications.isEmpty()) { - for (Authentication authentication : authentications) { - if (authentication.type() == SubjectType.USER) { - user = buildSubject(authentication); - } else { - service = buildSubject(authentication); - } - } - break; - } - } - return AuthenticationResponse.success(user, service); - } - - private Subject buildSubject(Authentication authentication) { - Subject.Builder subjectBuilder = Subject.builder(); - - subjectBuilder.principal(Principal.create(authentication.value())); - for (String role : authentication.roles()) { - subjectBuilder.addGrant(Role.create(role)); - } - for (String scope : authentication.scopes()) { - subjectBuilder.addGrant(Grant.builder() - .name(scope) - .type("scope") - .build()); - } - - return subjectBuilder.build(); - } - - @Override - public Collection> supportedAnnotations() { - return Set.of(Authentication.class); - } - - /** - * Authentication annotation. - */ - @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.METHOD}) - @Documented - @Inherited - @Repeatable(Authentications.class) - public @interface Authentication { - /** - * Name of the principal. - * - * @return principal name - */ - String value(); - - /** - * Type of the subject, defaults to user. - * - * @return type - */ - SubjectType type() default SubjectType.USER; - - /** - * Granted roles. - * @return array of roles - */ - String[] roles() default ""; - - /** - * Granted scopes. - * @return array of scopes - */ - String[] scopes() default ""; - } - - /** - * Repeatable annotation for {@link Authentication}. - */ - @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.METHOD}) - @Documented - @Inherited - public @interface Authentications { - /** - * Repeating annotation. - * @return annotations - */ - Authentication[] value(); - } -} diff --git a/examples/security/attribute-based-access-control/src/main/java/io/helidon/examples/security/abac/package-info.java b/examples/security/attribute-based-access-control/src/main/java/io/helidon/examples/security/abac/package-info.java deleted file mode 100644 index 19f2fcbcb69..00000000000 --- a/examples/security/attribute-based-access-control/src/main/java/io/helidon/examples/security/abac/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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 of Attribute based access control (ABAC). - */ -package io.helidon.examples.security.abac; diff --git a/examples/security/attribute-based-access-control/src/main/resources/META-INF/beans.xml b/examples/security/attribute-based-access-control/src/main/resources/META-INF/beans.xml deleted file mode 100644 index f2f827007a8..00000000000 --- a/examples/security/attribute-based-access-control/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/security/attribute-based-access-control/src/main/resources/application.yaml b/examples/security/attribute-based-access-control/src/main/resources/application.yaml deleted file mode 100644 index a6b15df009c..00000000000 --- a/examples/security/attribute-based-access-control/src/main/resources/application.yaml +++ /dev/null @@ -1,88 +0,0 @@ -# -# Copyright (c) 2017, 2024 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. -# - -# -# It is possible to provide default config values, here. -# - -server: - port: 8380 - -security: - providers: - - abac: - # prepares environment - # executes attribute validations - # validates that attributes were processed - # grants/denies access to resource - # - #### - # Combinations: - # # Will fail if any attribute is not validated and if any has failed validation - # fail-on-unvalidated: true - # fail-if-none-validated: true - # - # # Will fail if there is one or more attributes present and NONE of them is validated or if any has failed validation - # # Will NOT fail if there is at least one validated attribute and any number of not validated attributes (and NONE failed) - # fail-on-unvalidated: false - # fail-if-none-validated: true - # - # # Will fail if there is any attribute that failed validation - # # Will NOT fail if there are no failed validation or if there are NONE validated - # fail-on-unvalidated: false - # fail-if-none-validated: false - #### - # fail if an attribute was not validated (e.g. we do not know, whether it is valid or not) - # defaults to true - fail-on-unvalidated: true - # fail if none of the attributes were validated - # defaults to true - fail-if-none-validated: true -# policy-validator: -# validators: -# - class: "io.helidon.security.abac.policy.DefaultPolicyValidator" -# my-custom-policy-engine: -# some-key: "some value" -# another-key: "another value" - - atn: - class: "io.helidon.examples.security.abac.AtnProvider" - web-server: - paths: - - path: "/query" - audit: true - - path: "/noRoles" - methods: ["get"] - authenticate: true - - path: "/user[/{*}]" - methods: ["get"] - # implies authentication and authorization - abac: - scopes: ["calendar_read", "calendar_edit"] - time: - time-of-day: - - from: "08:15:00" - to: "12:00:00" - - from: "12:30" - to: "17:30" - days-of-week: ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY"] - policy: - #statement: "hasScopes('calendar_read','calendar_edit') AND timeOfDayBetween('8:15', '17:30')" - #ref: "service/policy_id" - statement: "object.owner == subject.principal.id" - resource: "com.oracle.ResourceProvider" - - - diff --git a/examples/security/attribute-based-access-control/src/main/resources/logging.properties b/examples/security/attribute-based-access-control/src/main/resources/logging.properties deleted file mode 100644 index 28f6591733f..00000000000 --- a/examples/security/attribute-based-access-control/src/main/resources/logging.properties +++ /dev/null @@ -1,19 +0,0 @@ -# -# Copyright (c) 2018, 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. -# - -handlers=io.helidon.logging.jul.HelidonConsoleHandler -.level=INFO -AUDIT.level=FINEST diff --git a/examples/security/basic-auth-with-static-content/README.md b/examples/security/basic-auth-with-static-content/README.md deleted file mode 100644 index 051ca33d842..00000000000 --- a/examples/security/basic-auth-with-static-content/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# Web Server Integration and Basic Authentication - -This example demonstrates integration of Web Server -based application with Security component and Basic authentication (from HttpAuthProvider), including -protection of a static resource. - -## Contents - -There are two examples with exactly the same behavior: -1. BasicExampleMain - shows how to programmatically secure application -2. BasicExampleConfigMain - shows how to secure application with configuration - 1. see src/main/resources/application.yaml for configuration - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-security-webserver-basic-auth.jar -``` - -Try the application: - -The application starts at the `8080` port -```shell -curl http://localhost:8080/public -curl -u "jill:changeit" http://localhost:8080/noRoles -curl -u "john:changeit" http://localhost:8080/user -curl -u "jack:changeit" http://localhost:8080/admin -curl -v -u "john:changeit" http://localhost:8080/deny -curl -u "jack:changeit" http://localhost:8080/noAuthn -``` diff --git a/examples/security/basic-auth-with-static-content/pom.xml b/examples/security/basic-auth-with-static-content/pom.xml deleted file mode 100644 index cd6eae80d0e..00000000000 --- a/examples/security/basic-auth-with-static-content/pom.xml +++ /dev/null @@ -1,112 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.security - helidon-examples-security-webserver-basic-auth - Helidon Examples Security HTTP Basic Auth with Static Content - - - This example demonstrates Integration of Web Server based application with Security component, HTTP Basic - Authentication, and static content support - - - - io.helidon.examples.security.basicauth.BasicExampleConfigMain - - - - - io.helidon.webserver - helidon-webserver-security - - - io.helidon.config - helidon-config-encryption - - - io.helidon.security.providers - helidon-security-providers-http-auth - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver - helidon-webserver-static-content - - - io.helidon.config - helidon-config - - - io.helidon.config - helidon-config-yaml - - - io.helidon.logging - helidon-logging-jul - runtime - - - io.helidon.webclient - helidon-webclient-security - test - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-core - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/security/basic-auth-with-static-content/src/main/java/io/helidon/examples/security/basicauth/BasicExampleBuilderMain.java b/examples/security/basic-auth-with-static-content/src/main/java/io/helidon/examples/security/basicauth/BasicExampleBuilderMain.java deleted file mode 100644 index b3577f3a76f..00000000000 --- a/examples/security/basic-auth-with-static-content/src/main/java/io/helidon/examples/security/basicauth/BasicExampleBuilderMain.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2020, 2024 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.security.basicauth; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import io.helidon.http.HttpMediaTypes; -import io.helidon.logging.common.LogConfig; -import io.helidon.security.Security; -import io.helidon.security.SecurityContext; -import io.helidon.security.providers.httpauth.HttpBasicAuthProvider; -import io.helidon.security.providers.httpauth.SecureUserStore; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.security.SecurityFeature; -import io.helidon.webserver.staticcontent.StaticContentService; - -/** - * Example using {@link io.helidon.common.Builder} approach instead of configuration based approach. - */ -public final class BasicExampleBuilderMain { - // simple approach to user storage - for real world, use data store... - private static final Map USERS = new HashMap<>(); - - static { - USERS.put("jack", new MyUser("jack", "changeit".toCharArray(), Set.of("user", "admin"))); - USERS.put("jill", new MyUser("jill", "changeit".toCharArray(), Set.of("user"))); - USERS.put("john", new MyUser("john", "changeit".toCharArray(), Set.of())); - } - - private BasicExampleBuilderMain() { - } - - /** - * Entry point, starts the server. - * - * @param args not used - */ - public static void main(String[] args) { - LogConfig.initClass(); - - WebServerConfig.Builder builder = WebServer.builder() - .port(8080); - setup(builder); - WebServer server = builder.build(); - - long t = System.nanoTime(); - server.start(); - long time = System.nanoTime() - t; - - System.out.printf(""" - Server started in %d ms - - Signature example: from builder - - "Users: - jack/password in roles: user, admin - jill/password in roles: user - john/password in no roles - - *********************** - ** Endpoints: ** - *********************** - - No authentication: http://localhost:8080/public - No roles required, authenticated: http://localhost:8080/noRoles - User role required: http://localhost:8080/user - Admin role required: http://localhost:8080/admin - Always forbidden (uses role nobody is in), audited: http://localhost:8080/deny - Admin role required, authenticated, authentication optional, audited \ - (always forbidden - challenge is not returned as authentication is optional): http://localhost:8080/noAuthn - Static content, requires user role: http://localhost:8080/static/index.html - - """, TimeUnit.MILLISECONDS.convert(time, TimeUnit.NANOSECONDS)); - } - - static void setup(WebServerConfig.Builder server) { - server.featuresDiscoverServices(false) - // only add security feature (as we do not use configuration, only features listed here will be available) - .addFeature(SecurityFeature.builder() - .security(buildSecurity()) - .defaults(SecurityFeature.authenticate()) - .build()) - .routing(routing -> routing - // must be configured first, to protect endpoints - .any("/static[/{*}]", SecurityFeature.rolesAllowed("user")) - .register("/static", StaticContentService.create("/WEB")) - .get("/noRoles", SecurityFeature.enforce()) - .get("/user[/{*}]", SecurityFeature.rolesAllowed("user")) - .get("/admin", SecurityFeature.rolesAllowed("admin")) - // audit is not enabled for GET methods by default - .get("/deny", SecurityFeature.rolesAllowed("deny").audit()) - // roles allowed imply authn and authz - .any("/noAuthn", SecurityFeature.rolesAllowed("admin") - .authenticationOptional() - .audit()) - .get("/{*}", (req, res) -> { - Optional securityContext = req.context().get(SecurityContext.class); - res.headers().contentType(HttpMediaTypes.PLAINTEXT_UTF_8); - res.send("Hello, you are: \n" + securityContext - .map(ctx -> ctx.user().orElse(SecurityContext.ANONYMOUS).toString()) - .orElse("Security context is null")); - })); - } - - private static Security buildSecurity() { - return Security.builder() - .addAuthenticationProvider( - HttpBasicAuthProvider.builder() - .realm("helidon") - .userStore(buildUserStore()), - "http-basic-auth") - .build(); - } - - private static SecureUserStore buildUserStore() { - return login -> Optional.ofNullable(USERS.get(login)); - } - - private record MyUser(String login, char[] password, Set roles) implements SecureUserStore.User { - - @Override - public boolean isPasswordValid(char[] password) { - return Arrays.equals(password(), password); - } - } -} diff --git a/examples/security/basic-auth-with-static-content/src/main/java/io/helidon/examples/security/basicauth/BasicExampleConfigMain.java b/examples/security/basic-auth-with-static-content/src/main/java/io/helidon/examples/security/basicauth/BasicExampleConfigMain.java deleted file mode 100644 index 3fe95257829..00000000000 --- a/examples/security/basic-auth-with-static-content/src/main/java/io/helidon/examples/security/basicauth/BasicExampleConfigMain.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.security.basicauth; - -import java.util.Optional; -import java.util.concurrent.TimeUnit; - -import io.helidon.config.Config; -import io.helidon.http.HttpMediaTypes; -import io.helidon.logging.common.LogConfig; -import io.helidon.security.SecurityContext; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.staticcontent.StaticContentService; - -/** - * Example using configuration based approach. - */ -public final class BasicExampleConfigMain { - private BasicExampleConfigMain() { - } - - /** - * Entry point, starts the server. - * - * @param args not used - */ - public static void main(String[] args) { - LogConfig.initClass(); - - WebServerConfig.Builder builder = WebServer.builder() - .port(8080); - setup(builder); - WebServer server = builder.build(); - - long t = System.nanoTime(); - server.start(); - long time = System.nanoTime() - t; - - System.out.printf(""" - Server started in %d ms - - Signature example: from builder - - "Users: - jack/password in roles: user, admin - jill/password in roles: user - john/password in no roles - - *********************** - ** Endpoints: ** - *********************** - - No authentication: http://localhost:8080/public - No roles required, authenticated: http://localhost:8080/noRoles - User role required: http://localhost:8080/user - Admin role required: http://localhost:8080/admin - Always forbidden (uses role nobody is in), audited: http://localhost:8080/deny - Admin role required, authenticated, authentication optional, audited \ - (always forbidden - challenge is not returned as authentication is optional): http://localhost:8080/noAuthn - Static content, requires user role: http://localhost:8080/static/index.html - - """, TimeUnit.MILLISECONDS.convert(time, TimeUnit.NANOSECONDS)); - } - - static void setup(WebServerConfig.Builder server) { - Config config = Config.create(); - - server.config(config.get("server")) - .routing(routing -> routing - .register("/static", StaticContentService.create("/WEB")) - .get("/{*}", (req, res) -> { - Optional securityContext = req.context().get(SecurityContext.class); - res.headers().contentType(HttpMediaTypes.PLAINTEXT_UTF_8); - res.send("Hello, you are: \n" + securityContext - .map(ctx -> ctx.user().orElse(SecurityContext.ANONYMOUS).toString()) - .orElse("Security context is null")); - })); - } -} diff --git a/examples/security/basic-auth-with-static-content/src/main/java/io/helidon/examples/security/basicauth/package-info.java b/examples/security/basic-auth-with-static-content/src/main/java/io/helidon/examples/security/basicauth/package-info.java deleted file mode 100644 index 6dfa24d18cc..00000000000 --- a/examples/security/basic-auth-with-static-content/src/main/java/io/helidon/examples/security/basicauth/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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 of basic authentication used with static content. - */ -package io.helidon.examples.security.basicauth; diff --git a/examples/security/basic-auth-with-static-content/src/main/resources/WEB/index.html b/examples/security/basic-auth-with-static-content/src/main/resources/WEB/index.html deleted file mode 100644 index 1d3ecc1d166..00000000000 --- a/examples/security/basic-auth-with-static-content/src/main/resources/WEB/index.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - -Hello, this is a static resource loaded from classpath. -

      -The following endpoints are available on this server: -

      - -The following users are configured: -
        -
      • jack/password in user and admin roles
      • -
      • jill/password in user roles
      • -
      • john/password that has no roles
      • -
      - - - diff --git a/examples/security/basic-auth-with-static-content/src/main/resources/application.yaml b/examples/security/basic-auth-with-static-content/src/main/resources/application.yaml deleted file mode 100644 index da4d6065f24..00000000000 --- a/examples/security/basic-auth-with-static-content/src/main/resources/application.yaml +++ /dev/null @@ -1,63 +0,0 @@ -# -# Copyright (c) 2020, 2024 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. -# - -# To configure an explicit port: -# server.port: 8080 - -server: - features: - security: - # Configuration of security integration with web server - defaults: - authenticate: true - paths: - - path: "/noRoles" - methods: [ "get" ] - - path: "/user[/{*}]" - methods: [ "get" ] - roles-allowed: [ "user" ] - - path: "/admin" - methods: [ "get" ] - roles-allowed: [ "admin" ] - - path: "/deny" - methods: [ "get" ] - roles-allowed: [ "deny" ] - audit: true - - path: "/noAuthn" - roles-allowed: [ "admin" ] - authentication-optional: true - audit: true - - path: "/static[/{*}]" - roles-allowed: "user" - -security: - config: - # Configuration of secured config (encryption of passwords in property files) - # Set to true for production - if set to true, clear text passwords will cause failure - require-encryption: false - providers: - - http-basic-auth: - realm: "helidon" - users: - - login: "jack" - password: "${CLEAR=changeit}" - roles: [ "user", "admin" ] - - login: "jill" - password: "${CLEAR=changeit}" - roles: [ "user" ] - - login: "john" - password: "${CLEAR=changeit}" - roles: [ ] diff --git a/examples/security/basic-auth-with-static-content/src/main/resources/logging.properties b/examples/security/basic-auth-with-static-content/src/main/resources/logging.properties deleted file mode 100644 index ed01d6773d2..00000000000 --- a/examples/security/basic-auth-with-static-content/src/main/resources/logging.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# Copyright (c) 2018, 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. -# - -handlers=io.helidon.logging.jul.HelidonConsoleHandler -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 -#All log level details -.level=INFO -AUDIT.level=FINEST diff --git a/examples/security/basic-auth-with-static-content/src/test/java/io/helidon/examples/security/basicauth/BasicExampleBuilderTest.java b/examples/security/basic-auth-with-static-content/src/test/java/io/helidon/examples/security/basicauth/BasicExampleBuilderTest.java deleted file mode 100644 index 369fe835890..00000000000 --- a/examples/security/basic-auth-with-static-content/src/test/java/io/helidon/examples/security/basicauth/BasicExampleBuilderTest.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.security.basicauth; - -import java.net.URI; - -import io.helidon.webserver.testing.junit5.SetUpServer; -import io.helidon.webserver.WebServerConfig; - -/** - * Unit test for {@link BasicExampleBuilderMain}. - */ -public class BasicExampleBuilderTest extends BasicExampleTest { - - public BasicExampleBuilderTest(URI uri) { - super(uri); - } - - @SetUpServer - public static void setup(WebServerConfig.Builder server) { - BasicExampleConfigMain.setup(server); - } -} diff --git a/examples/security/basic-auth-with-static-content/src/test/java/io/helidon/examples/security/basicauth/BasicExampleConfigTest.java b/examples/security/basic-auth-with-static-content/src/test/java/io/helidon/examples/security/basicauth/BasicExampleConfigTest.java deleted file mode 100644 index 94dcf7a6839..00000000000 --- a/examples/security/basic-auth-with-static-content/src/test/java/io/helidon/examples/security/basicauth/BasicExampleConfigTest.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.security.basicauth; - -import java.net.URI; - -import io.helidon.webserver.testing.junit5.SetUpServer; -import io.helidon.webserver.WebServerConfig; - -/** - * Unit test for {@link BasicExampleConfigMain}. - */ -public class BasicExampleConfigTest extends BasicExampleTest { - - public BasicExampleConfigTest(URI uri) { - super(uri); - } - - @SetUpServer - public static void setup(WebServerConfig.Builder server) { - BasicExampleConfigMain.setup(server); - } -} diff --git a/examples/security/basic-auth-with-static-content/src/test/java/io/helidon/examples/security/basicauth/BasicExampleTest.java b/examples/security/basic-auth-with-static-content/src/test/java/io/helidon/examples/security/basicauth/BasicExampleTest.java deleted file mode 100644 index 37a9a72414d..00000000000 --- a/examples/security/basic-auth-with-static-content/src/test/java/io/helidon/examples/security/basicauth/BasicExampleTest.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2020, 2024 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.security.basicauth; - -import java.net.URI; -import java.util.Set; - -import io.helidon.http.HeaderNames; -import io.helidon.http.Status; -import io.helidon.security.EndpointConfig; -import io.helidon.security.Security; -import io.helidon.security.providers.httpauth.HttpBasicAuthProvider; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webclient.security.WebClientSecurity; -import io.helidon.webserver.testing.junit5.ServerTest; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Abstract class with tests for this example (used by programmatic and config based tests). - */ -@ServerTest -public abstract class BasicExampleTest { - - private final Http1Client client; - - protected BasicExampleTest(URI uri) { - Security security = Security.builder() - .addProvider(HttpBasicAuthProvider.builder()) - .build(); - - WebClientSecurity securityService = WebClientSecurity.create(security); - - client = Http1Client.builder() - .baseUri(uri) - .addService(securityService) - .build(); - } - - //now for the tests - @Test - public void testPublic() { - //Must be accessible without authentication - try (Http1ClientResponse response = client.get().uri("/public").request()) { - assertThat(response.status(), is(Status.OK_200)); - String entity = response.entity().as(String.class); - assertThat(entity, containsString("")); - } - } - - @Test - public void testNoRoles() { - String uri = "/noRoles"; - - testNotAuthorized(uri); - - //Must be accessible with authentication - to everybody - testProtected(uri, "jack", "changeit", Set.of("admin", "user"), Set.of()); - testProtected(uri, "jill", "changeit", Set.of("user"), Set.of("admin")); - testProtected(uri, "john", "changeit", Set.of(), Set.of("admin", "user")); - } - - @Test - public void testUserRole() { - String uri = "/user"; - - testNotAuthorized(uri); - - //Jack and Jill allowed (user role) - testProtected(uri, "jack", "changeit", Set.of("admin", "user"), Set.of()); - testProtected(uri, "jill", "changeit", Set.of("user"), Set.of("admin")); - testProtectedDenied(uri, "john", "changeit"); - } - - @Test - public void testAdminRole() { - String uri = "/admin"; - - testNotAuthorized(uri); - - //Only jack is allowed - admin role... - testProtected(uri, "jack", "changeit", Set.of("admin", "user"), Set.of()); - testProtectedDenied(uri, "jill", "changeit"); - testProtectedDenied(uri, "john", "changeit"); - } - - @Test - public void testDenyRole() { - String uri = "/deny"; - - testNotAuthorized(uri); - - // nobody has the correct role - testProtectedDenied(uri, "jack", "changeit"); - testProtectedDenied(uri, "jill", "changeit"); - testProtectedDenied(uri, "john", "changeit"); - } - - @Test - public void getNoAuthn() { - String uri = "/noAuthn"; - //Must NOT be accessible without authentication - try (Http1ClientResponse response = client.get().uri(uri).request()) { - - // authentication is optional, so we are not challenged, only forbidden, as the role can never be there... - assertThat(response.status(), is(Status.FORBIDDEN_403)); - } - } - - private void testNotAuthorized(String uri) { - //Must NOT be accessible without authentication - try (Http1ClientResponse response = client.get().uri(uri).request()) { - - assertThat(response.status(), is(Status.UNAUTHORIZED_401)); - String header = response.headers().get(HeaderNames.WWW_AUTHENTICATE).get(); - - assertThat(header.toLowerCase(), containsString("basic")); - assertThat(header, containsString("helidon")); - } - } - - private Http1ClientResponse callProtected(String uri, String username, String password) { - // here we call the endpoint - return client.get() - .uri(uri) - .property(EndpointConfig.PROPERTY_OUTBOUND_ID, username) - .property(EndpointConfig.PROPERTY_OUTBOUND_SECRET, password) - .request(); - } - - @SuppressWarnings("SameParameterValue") - private void testProtectedDenied(String uri, String username, String password) { - try (Http1ClientResponse response = callProtected(uri, username, password)) { - assertThat(response.status(), is(Status.FORBIDDEN_403)); - } - } - - @SuppressWarnings("SameParameterValue") - private void testProtected(String uri, - String username, - String password, - Set expectedRoles, - Set invalidRoles) { - - try (Http1ClientResponse response = callProtected(uri, username, password)) { - - String entity = response.entity().as(String.class); - assertThat(response.status(), is(Status.OK_200)); - - // check login - assertThat(entity, containsString("id='" + username + "'")); - // check roles - expectedRoles.forEach(role -> assertThat(entity, containsString(":" + role))); - invalidRoles.forEach(role -> assertThat(entity, not(containsString(":" + role)))); - } - } -} diff --git a/examples/security/google-login/README.md b/examples/security/google-login/README.md deleted file mode 100644 index b4f5c355afb..00000000000 --- a/examples/security/google-login/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# Integration with Google login button - -This example demonstrates Integration with Google login button on a web page. - -## Contents - -There are two examples with exactly the same behavior -1. builder - shows how to programmatically secure application -2. config - shows how to secure application with configuration - 1. see src/main/resources/application.conf - -There is a static web page in src/main/resources/WEB with a page to login to Google. - -This example requires a Google client id to run. -Update the following files with your client id (it should support http://localhost:8080): -1. src/main/resources/application.yaml - set security.properties.google-client-id or override it in a file in ~/helidon/examples.yaml -2. src/main/resources/WEB/index.html - update the meta tag in header with name "google-signin-client_id" -3. src/main/java/io/helidon/security/examples/google/GoogleBuilderMain.java - update the client id in builder of provider - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-security-google-login.jar -``` diff --git a/examples/security/google-login/pom.xml b/examples/security/google-login/pom.xml deleted file mode 100644 index 4b109f17691..00000000000 --- a/examples/security/google-login/pom.xml +++ /dev/null @@ -1,112 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.security - helidon-examples-security-google-login - Helidon Examples Security Google Login - - - Example of Google login button integration with Security. - - - - io.helidon.examples.security.google.GoogleConfigMain - - - - - io.helidon.webserver - helidon-webserver-security - - - io.helidon.security.providers - helidon-security-providers-google-login - - - io.helidon.config - helidon-config-encryption - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver - helidon-webserver-static-content - - - io.helidon.bundles - helidon-bundles-config - - - io.helidon.logging - helidon-logging-jul - runtime - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - io.helidon.common.testing - helidon-common-testing-junit5 - test - - - io.helidon.config - helidon-config-testing - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-core - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/security/google-login/src/main/java/io/helidon/examples/security/google/GoogleBuilderMain.java b/examples/security/google-login/src/main/java/io/helidon/examples/security/google/GoogleBuilderMain.java deleted file mode 100644 index 2265c8fdb2e..00000000000 --- a/examples/security/google-login/src/main/java/io/helidon/examples/security/google/GoogleBuilderMain.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.security.google; - -import java.util.Optional; -import java.util.concurrent.TimeUnit; - -import io.helidon.http.HttpMediaTypes; -import io.helidon.logging.common.LogConfig; -import io.helidon.security.Security; -import io.helidon.security.SecurityContext; -import io.helidon.security.Subject; -import io.helidon.security.providers.google.login.GoogleTokenProvider; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.context.ContextFeature; -import io.helidon.webserver.security.SecurityFeature; -import io.helidon.webserver.staticcontent.StaticContentService; - -/** - * Google login button example main class using builders. - */ -@SuppressWarnings({"SpellCheckingInspection", "DuplicatedCode"}) -public final class GoogleBuilderMain { - - private GoogleBuilderMain() { - } - - /** - * Start the example. - * - * @param args ignored - */ - public static void main(String[] args) { - LogConfig.configureRuntime(); - WebServerConfig.Builder builder = WebServerConfig.builder(); - setup(builder); - WebServer server = builder.build(); - - long t = System.nanoTime(); - server.start(); - long time = System.nanoTime() - t; - - System.out.printf(""" - Server started in %d ms - Started server on localhost: %2$d - You can access this example at http://localhost:%2$d/index.html - - Check application.yaml in case you are behind a proxy to configure it - """, - TimeUnit.MILLISECONDS.convert(time, TimeUnit.NANOSECONDS), - server.port()); - } - - static void setup(WebServerConfig.Builder server) { - Security security = Security.builder() - .addProvider(GoogleTokenProvider.builder() - .clientId("your-client-id.apps.googleusercontent.com")) - .build(); - server.featuresDiscoverServices(false) - .addFeature(ContextFeature.create()) - .addFeature(SecurityFeature.builder() - .security(security) - .build()) - .routing(routing -> routing - .get("/rest/profile", SecurityFeature.authenticate(), - (req, res) -> { - Optional securityContext = req.context().get(SecurityContext.class); - res.headers().contentType(HttpMediaTypes.PLAINTEXT_UTF_8); - res.send("Response from builder based service, you are: \n" + securityContext - .flatMap(SecurityContext::user) - .map(Subject::toString) - .orElse("Security context is null")); - res.next(); - }) - .register(StaticContentService.create("/WEB"))); - } -} diff --git a/examples/security/google-login/src/main/java/io/helidon/examples/security/google/GoogleConfigMain.java b/examples/security/google-login/src/main/java/io/helidon/examples/security/google/GoogleConfigMain.java deleted file mode 100644 index 89b62713ae7..00000000000 --- a/examples/security/google-login/src/main/java/io/helidon/examples/security/google/GoogleConfigMain.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.security.google; - -import java.util.Optional; -import java.util.concurrent.TimeUnit; - -import io.helidon.config.Config; -import io.helidon.http.HttpMediaTypes; -import io.helidon.logging.common.LogConfig; -import io.helidon.security.SecurityContext; -import io.helidon.security.Subject; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.staticcontent.StaticContentService; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.file; - -/** - * Google login button example main class using configuration. - */ -@SuppressWarnings("DuplicatedCode") -public final class GoogleConfigMain { - - private GoogleConfigMain() { - } - - /** - * Start the example. - * - * @param args ignored - */ - public static void main(String[] args) { - LogConfig.configureRuntime(); - WebServerConfig.Builder builder = WebServerConfig.builder(); - setup(builder); - WebServer server = builder.build(); - - long t = System.nanoTime(); - server.start(); - long time = System.nanoTime() - t; - - System.out.printf(""" - Server started in %d ms - Started server on localhost: %2$d - You can access this example at http://localhost:%2$d/index.html - - Check application.yaml in case you are behind a proxy to configure it - """, - TimeUnit.MILLISECONDS.convert(time, TimeUnit.NANOSECONDS), - server.port()); - } - - static void setup(WebServerConfig.Builder server) { - Config config = buildConfig(); - server.config(config.get("server")) - .routing(routing -> routing - .get("/rest/profile", (req, res) -> { - Optional securityContext = req.context().get(SecurityContext.class); - res.headers().contentType(HttpMediaTypes.PLAINTEXT_UTF_8); - res.send("Response from config based service, you are: \n" + securityContext - .flatMap(SecurityContext::user) - .map(Subject::toString) - .orElse("Security context is null")); - }) - .register(StaticContentService.create("/WEB"))); - } - - private static Config buildConfig() { - return Config.builder() - .sources( - // you can use this file to override the defaults built-in - file(System.getProperty("user.home") + "/helidon/conf/examples.yaml").optional(), - // in jar file (see src/main/resources/application.yaml) - classpath("application.yaml")) - .build(); - } -} diff --git a/examples/security/google-login/src/main/java/io/helidon/examples/security/google/package-info.java b/examples/security/google-login/src/main/java/io/helidon/examples/security/google/package-info.java deleted file mode 100644 index 44ad9e8fde2..00000000000 --- a/examples/security/google-login/src/main/java/io/helidon/examples/security/google/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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 of integration of Google Login button with security. - */ -package io.helidon.examples.security.google; diff --git a/examples/security/google-login/src/main/resources/WEB/index.html b/examples/security/google-login/src/main/resources/WEB/index.html deleted file mode 100644 index e4af8b0b29c..00000000000 --- a/examples/security/google-login/src/main/resources/WEB/index.html +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - Google Login Provider - - - - - - - - - - - - - - - - - - - -
      - - - - - - - - - - -

      Login to Google.

      -
      -
      -
      - - -
      -
      -
      - - - diff --git a/examples/security/google-login/src/main/resources/WEB/static/js/google-app.js b/examples/security/google-login/src/main/resources/WEB/static/js/google-app.js deleted file mode 100644 index cb6775b9c78..00000000000 --- a/examples/security/google-login/src/main/resources/WEB/static/js/google-app.js +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2017, 2021 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. - */ - -(function () { - // new module with no dependencies - var app = angular.module('g', []); - - app.controller('GoogleController', ['$http', function ($http) { - this.callBackend = function () { - var accessToken = document.getElementById('gat_input').value; - - if (accessToken === "") { - console.log("No access token, not calling backend"); - alert("Please login before calling backend service"); - return; - } - console.log("Submit attempt to server: " + accessToken); - - $http({ - method: 'GET', - url: '/rest/profile', - headers: { - 'Authorization': "Bearer " + accessToken - } - }).success(function (data, status, headers, config) { - console.log('Successfully sent data to backend, received' + data); - alert(data); - }).error(function (data, status, headers, config) { - console.log('Failed to send data to backend. Status: ' + status); - alert(status + ", auth header: " + headers('WWW-Authenticate') + ", error: " + data); - }); - } - }]); -})(); diff --git a/examples/security/google-login/src/main/resources/application.yaml b/examples/security/google-login/src/main/resources/application.yaml deleted file mode 100644 index d0ff681e363..00000000000 --- a/examples/security/google-login/src/main/resources/application.yaml +++ /dev/null @@ -1,50 +0,0 @@ -# -# Copyright (c) 2016, 2020 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. -# - -security: - config.require-encryption: false - properties: - # This example loads overriding properties from ~/helidon/examples.yaml - # You may configure correct values in that file to leave this content intact - google-client-id: "your-app-id.apps.googleusercontent.com" - proxy-host: "" - providers: - - google-login: - # Create your own application in Google developer console - # Also update the client id configured in header of index.html - # Detailed how-to for login button (including links how to create an application): - # https://developers.google.com/identity/sign-in/web/sign-in - client-id: "${security.properties.google-client-id}" - # Defaults for Helidon - # realm: "helidon" - # Configure proxy host if needed - proxy-host: "${security.properties.proxy-host}" - # proxy-port: 80 - - # This is the default for GoogleTokenProvider - #token: - # header: "Authorization" - # or do not specify - then the whole header is considered to be the token value - # prefix: "bearer " - # optional alternative - looking for first matching group - # regexp: "bearer (.*)" - #} - web-server: - paths: - - path: "/rest/profile" - methods: ["get"] - authenticate: true - diff --git a/examples/security/google-login/src/main/resources/logging.properties b/examples/security/google-login/src/main/resources/logging.properties deleted file mode 100644 index aae115cc395..00000000000 --- a/examples/security/google-login/src/main/resources/logging.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2018, 2023 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. -# - -handlers=io.helidon.logging.jul.HelidonConsoleHandler -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 -.level=INFO -AUDIT.level=FINEST diff --git a/examples/security/google-login/src/test/java/io/helidon/examples/security/google/GoogleBuilderMainTest.java b/examples/security/google-login/src/test/java/io/helidon/examples/security/google/GoogleBuilderMainTest.java deleted file mode 100644 index 10afcd2fab4..00000000000 --- a/examples/security/google-login/src/test/java/io/helidon/examples/security/google/GoogleBuilderMainTest.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.security.google; - -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webserver.WebServerConfig; - -/** - * Unit test for {@link GoogleBuilderMain}. - */ -@ServerTest -public class GoogleBuilderMainTest extends GoogleMainTest { - - GoogleBuilderMainTest(Http1Client client) { - super(client); - } - - @SetUpServer - public static void setup(WebServerConfig.Builder server) { - GoogleBuilderMain.setup(server); - } -} diff --git a/examples/security/google-login/src/test/java/io/helidon/examples/security/google/GoogleConfigMainTest.java b/examples/security/google-login/src/test/java/io/helidon/examples/security/google/GoogleConfigMainTest.java deleted file mode 100644 index cc60df9b764..00000000000 --- a/examples/security/google-login/src/test/java/io/helidon/examples/security/google/GoogleConfigMainTest.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.security.google; - -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webserver.WebServerConfig; - -/** - * Unit test for {@link GoogleConfigMain}. - */ -@ServerTest -public class GoogleConfigMainTest extends GoogleMainTest { - - GoogleConfigMainTest(Http1Client client) { - super(client); - } - - @SetUpServer - public static void setup(WebServerConfig.Builder server) { - GoogleConfigMain.setup(server); - } -} diff --git a/examples/security/google-login/src/test/java/io/helidon/examples/security/google/GoogleMainTest.java b/examples/security/google-login/src/test/java/io/helidon/examples/security/google/GoogleMainTest.java deleted file mode 100644 index 3d3fe61d49a..00000000000 --- a/examples/security/google-login/src/test/java/io/helidon/examples/security/google/GoogleMainTest.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.security.google; - -import io.helidon.http.HeaderNames; -import io.helidon.http.Status; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; - -import org.junit.jupiter.api.Test; - -import static io.helidon.common.testing.junit5.OptionalMatcher.optionalValue; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Google login common unit tests. - */ -public abstract class GoogleMainTest { - private final Http1Client client; - - GoogleMainTest(Http1Client client) { - this.client = client; - } - - @Test - public void testEndpoint() { - try (Http1ClientResponse response = client.get("/rest/profile").request()) { - - assertThat(response.status(), is(Status.UNAUTHORIZED_401)); - assertThat(response.headers().first(HeaderNames.WWW_AUTHENTICATE), - optionalValue(is("Bearer realm=\"helidon\",scope=\"openid profile email\""))); - } - } -} diff --git a/examples/security/idcs-login/README.md b/examples/security/idcs-login/README.md deleted file mode 100644 index 5076dea8669..00000000000 --- a/examples/security/idcs-login/README.md +++ /dev/null @@ -1,76 +0,0 @@ -# Security integration with IDCS - -This example demonstrates integration with IDCS (Oracle identity service, integrated with Open ID Connect provider). - -## Contents - -This project contains two samples, one (IdcsMain.java) which is configured via the application.yaml file and a second example (IdcsBuilderMain.java) which is configured in code. - -When configured the example exposes two HTTP endpoints `/jersey`, a rest endpoint protected by an IDCS application (with two scopes) and a second endpoint (/rest/profile) which is not protected. - -### IDCS Configuration - -Edit application.yaml for IdcsMain.java or OidcConfig variable definition for IdcsBuilderMain.java sample - -1. Log in to the IDCS console and create a new application of type "confidential app" -2. Within **Resources** - 1. Create two resources called `first_scope` and `second_scope` - 2. Primary Audience = `http://localhost:7987/"` (ensure there is a trailing /) -3. Within **Client Configuration** - 1. Register a client - 2. Allowed Grant Types = Client Credentials,JWT Assertion, Refresh Token, Authorization Code - 3. Check "Allow non-HTTPS URLs" - 4. Set Redirect URL to `http://localhost:7987/oidc/redirect` - 5. Client Type = Confidential - 6. Add all Scopes defined in the resources section - 7. Set allowed operations to `Introspect` - 8. Set Post Logout Redirect URL to `http://localhost:7987/loggedout` - -Ensure you save and *activate* the application - -### Code Configuration - -Edit application.yaml for IdcsMain.java or OidcConfig variable definition for IdcsBuilderMain.java sample - - 1. idcs-uri : Base URL of your idcs instance, usually something like https://idcs-.identity.oraclecloud.com - 2. idcs-client-id : This is obtained from your IDCS application in the IDCS console - 3. idcs-client-secret : This is obtained from your IDCS application in the IDCS console - 4. frontend-uri : This is the base URL of your application when run, e.g. `http://localhost:7987` - 5. proxy-host : Your proxy server if needed - 6. scope-audience : This is the scope audience which MUST match the primary audience in the IDCS resource, recommendation is not to have a trailing slash (/) - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-security-oidc.jar -``` - -Try the endpoints: - -3. Open http://localhost:7987/rest/profile in your browser. This should present - you with a response highlighting your logged in role (null) correctly as you are not logged in -4. Open `http://localhost:7987/oidc/logout` in your browser. This will log you out from your IDCS and Helidon sessions - -## Calling Sample from Postman - -Now that everything is setup it is possible to call the sample from tools like postman - -1. Create new REST call for your service , e.g. `http://localhost:7987/jersey` -2. Set authentication to oauth 2.0 -3. Press the "Get New Access Token" button - 1. Grant Type should be "Password Credentials" - 2. IDCS Access token URI should be `https://.identity.oraclecloud.com/oauth2/v1/token` - 3. ClientID and Client Secret should be obtained from IDCS and is the same that is configured in the app - 4. Scopes should be a "space" delimited list of scopes prefixed by audience , e.g. `http://localhost:7987/first_scope http://localhost:7987/second_scope` - 5. Client Authentication "Send as Basic Auth Header" -4. Request Token (If you get an error check the postman developer console) -5. Once you have a token ensure you press the "Use token" button -6. Execute your rest call - -## Troubleshooting - -#### Upon redirect to IDCS login page you receive a message indicating the scope isn't found - -- Check that *both* scope names in JerseyResource (first_scope and second_scope) exist in your IDCS application -- Check that the `primary audience` config value in IDCS contains a trailing / and the `front-end-url` in the config file does not diff --git a/examples/security/idcs-login/pom.xml b/examples/security/idcs-login/pom.xml deleted file mode 100644 index c98380f7a30..00000000000 --- a/examples/security/idcs-login/pom.xml +++ /dev/null @@ -1,133 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.security - helidon-examples-security-oidc - Helidon Examples Security IDCS Login - - - Example of login with IDCS using the OIDC provider, storing the identity in a cookie - - - - io.helidon.examples.security.idcs.IdcsMain - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.http.media - helidon-http-media-jsonp - - - - io.helidon.security.providers - helidon-security-providers-oidc - - - - io.helidon.security.providers - helidon-security-providers-idcs-mapper - - - - io.helidon.security.providers - helidon-security-providers-abac - - - - io.helidon.security.abac - helidon-security-abac-scope - - - - io.helidon.security.abac - helidon-security-abac-role - - - - io.helidon.webserver - helidon-webserver-security - - - - io.helidon.config - helidon-config-encryption - - - io.helidon.config - helidon-config-yaml - - - io.smallrye - jandex - runtime - true - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-core - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/security/idcs-login/src/main/java/io/helidon/examples/security/idcs/IdcsBuilderMain.java b/examples/security/idcs-login/src/main/java/io/helidon/examples/security/idcs/IdcsBuilderMain.java deleted file mode 100644 index 0bbb2ee6f7b..00000000000 --- a/examples/security/idcs-login/src/main/java/io/helidon/examples/security/idcs/IdcsBuilderMain.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.security.idcs; - -import java.net.URI; -import java.util.Optional; -import java.util.concurrent.TimeUnit; - -import io.helidon.common.context.Contexts; -import io.helidon.config.Config; -import io.helidon.http.HttpMediaTypes; -import io.helidon.logging.common.LogConfig; -import io.helidon.security.Security; -import io.helidon.security.SecurityContext; -import io.helidon.security.Subject; -import io.helidon.security.providers.idcs.mapper.IdcsRoleMapperProvider; -import io.helidon.security.providers.oidc.OidcFeature; -import io.helidon.security.providers.oidc.OidcProvider; -import io.helidon.security.providers.oidc.common.OidcConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.file; - -/** - * IDCS Login example main class using configuration . - */ -@SuppressWarnings("HttpUrlsUsage") -public final class IdcsBuilderMain { - - // do not change this constant, unless you modify configuration - // of IDCS application redirect URI - static final int PORT = 7987; - - private IdcsBuilderMain() { - } - - /** - * Start the example. - * - * @param args ignored - */ - public static void main(String[] args) { - LogConfig.configureRuntime(); - - WebServerConfig.Builder builder = WebServer.builder(); - setup(builder); - WebServer server = builder.build(); - - long t = System.nanoTime(); - server.start(); - long time = System.nanoTime() - t; - - System.out.printf(""" - Server started in %2$d ms - - Started server on localhost:%1$d - You can access this example at http://localhost:%1$d/rest/profile - - Check application.yaml in case you are behind a proxy to configure it - """, server.port(), TimeUnit.MILLISECONDS.convert(time, TimeUnit.NANOSECONDS)); - } - - static void setup(WebServerConfig.Builder server) { - Config config = buildConfig(); - - OidcConfig oidcConfig = OidcConfig.builder() - .clientId("clientId.of.your.application") - .clientSecret("clientSecret.of.your.application") - .identityUri(URI.create( - "https://idcs-tenant-id.identity.oracle.com")) - //.proxyHost("proxy.proxy.com") - .frontendUri("http://your.host:your.port") - // tell us it is IDCS, so we can modify the behavior - .serverType("idcs") - .build(); - - Security security = Security.builder() - .addProvider(OidcProvider.create(oidcConfig)) - .addProvider(IdcsRoleMapperProvider.builder() - .config(config) - .oidcConfig(oidcConfig)) - .build(); - // security needs to be available for other features, such as server security feature - Contexts.globalContext().register(security); - - server.port(PORT) - .routing(routing -> routing - // IDCS requires a web resource for redirects - .addFeature(OidcFeature.create(config)) - // web server does not (yet) have possibility to configure routes in config files, so explicit... - .get("/rest/profile", (req, res) -> { - Optional securityContext = req.context().get(SecurityContext.class); - res.headers().contentType(HttpMediaTypes.PLAINTEXT_UTF_8); - res.send("Response from builder based service, you are: \n" + securityContext - .flatMap(SecurityContext::user) - .map(Subject::toString) - .orElse("Security context is null")); - })); - } - - private static Config buildConfig() { - return Config.builder() - .sources( - // you can use this file to override the defaults built-in - file(System.getProperty("user.home") + "/helidon/conf/examples.yaml").optional(), - // in jar file (see src/main/resources/application.yaml) - classpath("application.yaml")) - .build(); - } -} diff --git a/examples/security/idcs-login/src/main/java/io/helidon/examples/security/idcs/IdcsMain.java b/examples/security/idcs-login/src/main/java/io/helidon/examples/security/idcs/IdcsMain.java deleted file mode 100644 index 826fefa154a..00000000000 --- a/examples/security/idcs-login/src/main/java/io/helidon/examples/security/idcs/IdcsMain.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.security.idcs; - -import java.util.Optional; -import java.util.concurrent.TimeUnit; - -import io.helidon.common.context.Contexts; -import io.helidon.config.Config; -import io.helidon.http.HttpMediaTypes; -import io.helidon.logging.common.LogConfig; -import io.helidon.security.Security; -import io.helidon.security.SecurityContext; -import io.helidon.security.Subject; -import io.helidon.security.providers.oidc.OidcFeature; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.file; - -/** - * IDCS Login example main class using configuration . - */ -public final class IdcsMain { - - private IdcsMain() { - } - - /** - * Start the example. - * - * @param args ignored - */ - public static void main(String[] args) { - LogConfig.configureRuntime(); - - WebServerConfig.Builder builder = WebServer.builder(); - setup(builder); - WebServer server = builder.build(); - - long t = System.nanoTime(); - server.start(); - long time = System.nanoTime() - t; - - System.out.printf(""" - Server started in %2$d ms - - Started server on localhost:%1$d - You can access this example at http://localhost:%1$d/rest/profile - - Check application.yaml in case you are behind a proxy to configure it - """, server.port(), TimeUnit.MILLISECONDS.convert(time, TimeUnit.NANOSECONDS)); - } - - static void setup(WebServerConfig.Builder server) { - Config config = buildConfig(); - - Security security = Security.create(config.get("security")); - // this is needed for proper encryption/decryption of cookies - Contexts.globalContext().register(security); - - server.config(config) - .routing(routing -> routing - // IDCS requires a web resource for redirects - .addFeature(OidcFeature.create(config)) - // web server does not (yet) have possibility to configure routes in config files, so explicit... - .get("/rest/profile", (req, res) -> { - Optional securityContext = req.context().get(SecurityContext.class); - res.headers().contentType(HttpMediaTypes.PLAINTEXT_UTF_8); - res.send("Response from config based service, you are: \n" + securityContext - .flatMap(SecurityContext::user) - .map(Subject::toString) - .orElse("Security context is null")); - }) - .get("/loggedout", (req, res) -> res.send("You have been logged out"))); - } - - private static Config buildConfig() { - return Config.builder() - .sources( - // you can use this file to override the defaults built-in - file(System.getProperty("user.home") + "/helidon/conf/examples.yaml").optional(), - // in jar file (see src/main/resources/application.yaml) - classpath("application.yaml")) - .build(); - } -} diff --git a/examples/security/idcs-login/src/main/java/io/helidon/examples/security/idcs/package-info.java b/examples/security/idcs-login/src/main/java/io/helidon/examples/security/idcs/package-info.java deleted file mode 100644 index 715b09269c1..00000000000 --- a/examples/security/idcs-login/src/main/java/io/helidon/examples/security/idcs/package-info.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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 showcasing integration of web server with IDCS server, using Open ID Connect security provider. - * There is another example in "microprofile" directory that shows the same integration for - * a MicroProfile based application. - */ -package io.helidon.examples.security.idcs; diff --git a/examples/security/idcs-login/src/main/resources/application.yaml b/examples/security/idcs-login/src/main/resources/application.yaml deleted file mode 100644 index 3143f33f23b..00000000000 --- a/examples/security/idcs-login/src/main/resources/application.yaml +++ /dev/null @@ -1,67 +0,0 @@ -# -# Copyright (c) 2018, 2024 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: 7987 - features: - security: - # protected paths on the web server - do not include paths served by Jersey, as those are protected directly - paths: - - path: "/rest/profile" - methods: [ "get" ] - authenticate: true - roles-allowed: [ "my_admins" ] - # abac: - # scopes: ["first_scope", "second_scope"] - -security: - config.require-encryption: false - properties: - # This is a nice way to be able to override this with local properties or env-vars - idcs-uri: "https://your-tenant-id.identity.oracle.com" - idcs-client-id: "your-client-id" - idcs-client-secret: "${CLEAR=changeit}" - proxy-host: "" - providers: - - abac: - # Adds ABAC Provider - it does not require any configuration - - oidc: - client-id: "${security.properties.idcs-client-id}" - client-secret: "${security.properties.idcs-client-secret}" - identity-uri: "${security.properties.idcs-uri}" - # A prefix used for custom scopes - scope-audience: "http://localhost:7987/test-application" - proxy-host: "${security.properties.proxy-host}" - # Used as a base for redirects back to us (based on Host header now, so no need to explicitly define it) - # If explicitly defined, will override host header - # frontend-uri: "http://localhost:7987" - # support for non-public signature JWK (and maybe other IDCS specific handling) - server-type: "idcs" - logout-enabled: true - # Can define just a path, host will be taken from header - post-logout-uri: "/loggedout" - # We want to redirect to login page (and token can be received either through cookie or header) - redirect: true - - idcs-role-mapper: - multitenant: false - oidc-config: - # we must repeat IDCS configuration, as in this case - # IDCS serves both as open ID connect authenticator and - # as a role mapper. Using minimal configuration here - client-id: "${security.properties.idcs-client-id}" - client-secret: "${security.properties.idcs-client-secret}" - identity-uri: "${security.properties.idcs-uri}" - diff --git a/examples/security/idcs-login/src/main/resources/logging.properties b/examples/security/idcs-login/src/main/resources/logging.properties deleted file mode 100644 index 78202ff9364..00000000000 --- a/examples/security/idcs-login/src/main/resources/logging.properties +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2018, 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. -# - -handlers=io.helidon.logging.jul.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 - -.level=INFO -AUDIT.level=FINEST -io.helidon.security.level=FINEST - diff --git a/examples/security/outbound-override/README.md b/examples/security/outbound-override/README.md deleted file mode 100644 index c4692698b77..00000000000 --- a/examples/security/outbound-override/README.md +++ /dev/null @@ -1,21 +0,0 @@ - -# Helidon Security Outbound Override Example - -Example that propagates identity, and on one endpoint explicitly -sets the username and password. - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-security-outbound-override.jar -``` - -Try the endpoints (port is random, shall be replaced accordingly): -```shell -export PORT=35973 -curl -u "jack:changeit" http://localhost:${PORT}/propagate -curl -u "jack:changeit" http://localhost:${PORT}/override -curl -u "jill:changeit" http://localhost:${PORT}/propagate -curl -u "jill:changeit" http://localhost:${PORT}/override -``` diff --git a/examples/security/outbound-override/pom.xml b/examples/security/outbound-override/pom.xml deleted file mode 100644 index 5390fe1f365..00000000000 --- a/examples/security/outbound-override/pom.xml +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.security - 4.0.0 - helidon-examples-security-outbound-override - Helidon Examples Security Outbound Override - - - io.helidon.security.examples.outbound.OutboundOverrideExample - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver - helidon-webserver-security - - - io.helidon.webclient - helidon-webclient - - - io.helidon.webclient - helidon-webclient-security - - - io.helidon.security.providers - helidon-security-providers-http-auth - - - io.helidon.security.providers - helidon-security-providers-jwt - - - io.helidon.bundles - helidon-bundles-config - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/JwtOverrideService.java b/examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/JwtOverrideService.java deleted file mode 100644 index f7b6053ec15..00000000000 --- a/examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/JwtOverrideService.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2023 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.security.examples.outbound; - -import io.helidon.security.EndpointConfig; -import io.helidon.security.SecurityContext; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.security.WebClientSecurity; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -final class JwtOverrideService implements HttpService { - - private final Http1Client client = Http1Client.builder() - .addService(WebClientSecurity.create()) - .build(); - - @Override - public void routing(HttpRules rules) { - rules.get("/override", this::override) - .get("/propagate", this::propagate); - } - - private void override(ServerRequest req, ServerResponse res) { - SecurityContext context = req.context() - .get(SecurityContext.class) - .orElseThrow(() -> new RuntimeException("Security not configured")); - - WebServer server = req.context() - .get(WebServer.class) - .orElseThrow(() -> new RuntimeException("WebServer not found in context")); - - String result = client.get("http://localhost:" + server.port("backend") + "/hello") - .property(EndpointConfig.PROPERTY_OUTBOUND_ID, "jill") - .requestEntity(String.class); - - res.send("You are: " + context.userName() + ", backend service returned: " + result); - } - - private void propagate(ServerRequest req, ServerResponse res) { - SecurityContext context = req.context() - .get(SecurityContext.class) - .orElseThrow(() -> new RuntimeException("Security not configured")); - - WebServer server = req.context() - .get(WebServer.class) - .orElseThrow(() -> new RuntimeException("WebServer not found in context")); - - String result = client.get("http://localhost:" + server.port("backend") + "/hello") - .requestEntity(String.class); - - res.send("You are: " + context.userName() + ", backend service returned: " + result); - } -} diff --git a/examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/OutboundOverrideExample.java b/examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/OutboundOverrideExample.java deleted file mode 100644 index b79d5519aa8..00000000000 --- a/examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/OutboundOverrideExample.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2018, 2024 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.security.examples.outbound; - -import java.util.concurrent.TimeUnit; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.security.Principal; -import io.helidon.security.SecurityContext; -import io.helidon.security.Subject; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.context.ContextFeature; -import io.helidon.webserver.security.SecurityHttpFeature; - -/** - * Creates two services. - *

      - * First service invokes the second with outbound security. - * There are two endpoints: - *

        - *
      • one that does simple identity propagation and one that uses an explicit username and password
      • - *
      • one that uses basic authentication both to authenticate users and to propagate identity.
      • - *
      - */ -public final class OutboundOverrideExample { - - private OutboundOverrideExample() { - } - - /** - * Example that propagates identity and on one endpoint explicitly sets the username and password. - * - * @param args ignored - */ - public static void main(String[] args) { - WebServerConfig.Builder builder = WebServer.builder(); - setup(builder); - WebServer server = builder.build(); - - long t = System.nanoTime(); - server.start(); - long time = System.nanoTime() - t; - - server.context().register(server); - - System.out.printf(""" - Server started in %3d ms - - *********************** - ** Endpoints: ** - *********************** - - http://localhost:%1d/propagate - http://localhost:%1d/override - - Backend service started on: http://localhost:%2d/hello - - """, TimeUnit.MILLISECONDS.convert(time, TimeUnit.NANOSECONDS), - server.port(), server.port(), server.port("backend")); - } - - static void setup(WebServerConfig.Builder server) { - Config clientConfig = Config.create(ConfigSources.classpath("client-service.yaml")); - Config backendConfig = Config.create(ConfigSources.classpath("backend-service.yaml")); - - // as we use the security http feature directly, we cannot use discovered security feature - // this is a unique case where we combine two sets of server set-ups in a single webserver - server.featuresDiscoverServices(false) - // context feature is a pre-requisite of security - .addFeature(ContextFeature.create()) - .config(clientConfig.get("security")) - .routing(routing -> routing - .addFeature(SecurityHttpFeature.create(clientConfig.get("security.web-server"))) - .register(new OverrideService())) - - // backend that prints the current user - .putSocket("backend", socket -> socket - .routing(routing -> routing - .addFeature(SecurityHttpFeature.create(backendConfig.get("security.web-server"))) - .get("/hello", (req, res) -> { - String username = req.context() - .get(SecurityContext.class) - .flatMap(SecurityContext::user) - .map(Subject::principal) - .map(Principal::getName) - .orElse("Anonymous"); - res.send(username); - }))); - } -} diff --git a/examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/OutboundOverrideJwtExample.java b/examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/OutboundOverrideJwtExample.java deleted file mode 100644 index 635fa5444fc..00000000000 --- a/examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/OutboundOverrideJwtExample.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2018, 2024 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.security.examples.outbound; - -import java.util.concurrent.TimeUnit; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.http.HeaderNames; -import io.helidon.security.Principal; -import io.helidon.security.SecurityContext; -import io.helidon.security.Subject; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.context.ContextFeature; -import io.helidon.webserver.security.SecurityHttpFeature; - -/** - * Creates two services. - * First service invokes the second with outbound security. - * There are two endpoints: - *
        - *
      • One that does simple identity propagation and one that uses an explicit username
      • - *
      • One that uses basic authentication to authenticate users and JWT to propagate identity
      • - *
      - one that does simple identity propagation and one that uses an explicit username. - *

      - * The difference between this example and basic authentication example: - *

        - *
      • Configuration files (this example uses ones with -jwt.yaml suffix)
      • - *
      • Client property used to override username
      • - *
      - */ -public final class OutboundOverrideJwtExample { - - private OutboundOverrideJwtExample() { - } - - /** - * Example that propagates identity and on one endpoint explicitly sets the username and password. - * - * @param args ignored - */ - public static void main(String[] args) { - WebServerConfig.Builder builder = WebServer.builder(); - setup(builder); - WebServer server = builder.build(); - - long t = System.nanoTime(); - server.start(); - long time = System.nanoTime() - t; - - server.context().register(server); - - System.out.printf(""" - Server started in %3$d ms - - *********************** - ** Endpoints: ** - *********************** - - http://localhost:%1$d/propagate - http://localhost:%1$d/override - - Backend service started on: http://localhost:%2$d/hello - - """, - server.port(), - server.port("backend"), - TimeUnit.MILLISECONDS.convert(time, TimeUnit.NANOSECONDS)); - } - - static void setup(WebServerConfig.Builder server) { - Config clientConfig = Config.create(ConfigSources.classpath("client-service-jwt.yaml")); - Config backendConfig = Config.create(ConfigSources.classpath("backend-service-jwt.yaml")); - - // as we use the security http feature directly, we cannot use discovered security feature - // this is a unique case where we combine two sets of server set-ups in a single webserver - server.featuresDiscoverServices(false) - // context feature is a pre-requisite of security - .addFeature(ContextFeature.create()) - .routing(routing -> routing - .addFeature(SecurityHttpFeature.create(clientConfig.get("security.web-server"))) - .register(new JwtOverrideService())) - - // backend that prints the current user - .putSocket("backend", socket -> socket - .routing(routing -> routing - .addFeature(SecurityHttpFeature.create(backendConfig.get("security.web-server"))) - .get("/hello", (req, res) -> { - - // This is the token. It should be bearer - req.headers().first(HeaderNames.AUTHORIZATION) - .ifPresent(System.out::println); - - String username = req.context() - .get(SecurityContext.class) - .flatMap(SecurityContext::user) - .map(Subject::principal) - .map(Principal::getName) - .orElse("Anonymous"); - - res.send(username); - }))); - } -} diff --git a/examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/OverrideService.java b/examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/OverrideService.java deleted file mode 100644 index 94acb5daa6d..00000000000 --- a/examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/OverrideService.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2023, 2024 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.security.examples.outbound; - -import io.helidon.security.EndpointConfig; -import io.helidon.security.SecurityContext; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.security.WebClientSecurity; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -class OverrideService implements HttpService { - - private final Http1Client client = Http1Client.builder() - .addService(WebClientSecurity.create()) - .build(); - - @Override - public void routing(HttpRules rules) { - rules.get("/override", this::override) - .get("/propagate", this::propagate); - } - - - private void override(ServerRequest req, ServerResponse res) { - SecurityContext context = req.context() - .get(SecurityContext.class) - .orElseThrow(() -> new RuntimeException("Security not configured")); - - WebServer server = req.context() - .get(WebServer.class) - .orElseThrow(() -> new RuntimeException("WebServer not found in context")); - - String result = client.get("http://localhost:" + server.port("backend") + "/hello") - .property(EndpointConfig.PROPERTY_OUTBOUND_ID, "jill") - .property(EndpointConfig.PROPERTY_OUTBOUND_SECRET, "changeit") - .requestEntity(String.class); - - res.send("You are: " + context.userName() + ", backend service returned: " + result + "\n"); - } - - private void propagate(ServerRequest req, ServerResponse res) { - SecurityContext context = req.context() - .get(SecurityContext.class) - .orElseThrow(() -> new RuntimeException("Security not configured")); - - WebServer server = req.context() - .get(WebServer.class) - .orElseThrow(() -> new RuntimeException("WebServer not found in context")); - - String result = client.get("http://localhost:" + server.port("backend") + "/hello") - .requestEntity(String.class); - - res.send("You are: " + context.userName() + ", backend service returned: " + result + "\n"); - } - -} diff --git a/examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/package-info.java b/examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/package-info.java deleted file mode 100644 index 230eebf33fd..00000000000 --- a/examples/security/outbound-override/src/main/java/io/helidon/security/examples/outbound/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2018, 2021 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 to show how to override default settings of an outbound provider. - */ -package io.helidon.security.examples.outbound; diff --git a/examples/security/outbound-override/src/main/resources/backend-service-jwt.yaml b/examples/security/outbound-override/src/main/resources/backend-service-jwt.yaml deleted file mode 100644 index 5f45ed86ce9..00000000000 --- a/examples/security/outbound-override/src/main/resources/backend-service-jwt.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2018, 2023 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. -# - -security: - providers: - - jwt: - atn-token: - jwk.resource.resource-path: "verifying-jwk.json" - jwt-audience: "http://example.helidon.io" - web-server: - defaults: - authenticate: true - paths: - - path: "/hello" - methods: ["get"] diff --git a/examples/security/outbound-override/src/main/resources/backend-service.yaml b/examples/security/outbound-override/src/main/resources/backend-service.yaml deleted file mode 100644 index e40cfd46a69..00000000000 --- a/examples/security/outbound-override/src/main/resources/backend-service.yaml +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright (c) 2018, 2024 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. -# - -security: - providers: - - http-basic-auth: - users: - - login: "jack" - password: "changeit" - roles: ["user", "admin"] - - login: "jill" - password: "changeit" - roles: ["user"] - web-server: - defaults: - authenticate: true - paths: - - path: "/hello" - methods: ["get"] - roles-allowed: "user" diff --git a/examples/security/outbound-override/src/main/resources/client-service-jwt.yaml b/examples/security/outbound-override/src/main/resources/client-service-jwt.yaml deleted file mode 100644 index c4d11dba67a..00000000000 --- a/examples/security/outbound-override/src/main/resources/client-service-jwt.yaml +++ /dev/null @@ -1,63 +0,0 @@ -# -# Copyright (c) 2018, 2024 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. -# - -security: - provider-policy: - type: "COMPOSITE" - authentication: - - name: "http-basic-auth" - outbound: - - name: "jwt" - providers: - - http-basic-auth: - users: - - login: "john" - password: "changeit" - roles: ["admin"] - - login: "jack" - password: "changeit" - roles: ["user", "admin"] - - login: "jill" - password: "changeit" - roles: ["user"] - - jwt: - allow-impersonation: true - atn-token: - # we are not interested in inbound tokens - verify-signature: false - sign-token: - jwk.resource.resource-path: "signing-jwk.json" - jwt-issuer: "example.helidon.io" - outbound: - - name: "propagate-identity" - jwk-kid: "example" - jwt-kid: "helidon" - jwt-audience: "http://example.helidon.io" - outbound-token: - header: "Authorization" - format: "bearer %1$s" - outbound: - - name: "propagate-all" - web-server: - defaults: - authenticate: true - paths: - - path: "/propagate" - methods: ["get"] - roles-allowed: "user" - - path: "/override" - methods: ["get"] - roles-allowed: "user" \ No newline at end of file diff --git a/examples/security/outbound-override/src/main/resources/client-service.yaml b/examples/security/outbound-override/src/main/resources/client-service.yaml deleted file mode 100644 index 0219ab30eeb..00000000000 --- a/examples/security/outbound-override/src/main/resources/client-service.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# -# Copyright (c) 2018, 2024 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. -# - -security: - providers: - - http-basic-auth: - users: - - login: "john" - password: "changeit" - roles: ["admin"] - - login: "jack" - password: "changeit" - roles: ["user", "admin"] - - login: "jill" - password: "changeit" - roles: ["user"] - outbound: - - name: "propagate-all" - web-server: - defaults: - authenticate: true - paths: - - path: "/propagate" - methods: ["get"] - roles-allowed: "user" - - path: "/override" - methods: ["get"] - roles-allowed: "user" \ No newline at end of file diff --git a/examples/security/outbound-override/src/main/resources/logging.properties b/examples/security/outbound-override/src/main/resources/logging.properties deleted file mode 100644 index 8046694e624..00000000000 --- a/examples/security/outbound-override/src/main/resources/logging.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2023 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. -# - -handlers = java.util.logging.ConsoleHandler - -java.util.logging.ConsoleHandler.level = FINEST -java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter -java.util.logging.SimpleFormatter.format = [%1$tc] %4$s: %2$s - %5$s %6$s%n - -.level = INFO diff --git a/examples/security/outbound-override/src/main/resources/signing-jwk.json b/examples/security/outbound-override/src/main/resources/signing-jwk.json deleted file mode 100644 index 09df45ed5b0..00000000000 --- a/examples/security/outbound-override/src/main/resources/signing-jwk.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "keys": [ - { - "kty": "oct", - "kid": "example", - "alg": "HS256", - "key_ops": [ - "sign", - "verify" - ], - "k": "FdFYFzERwC2uCBB46pZQi4GG85LujR8obt-KWRBICVQ" - } - ] -} \ No newline at end of file diff --git a/examples/security/outbound-override/src/main/resources/verifying-jwk.json b/examples/security/outbound-override/src/main/resources/verifying-jwk.json deleted file mode 100644 index 5bfc903024a..00000000000 --- a/examples/security/outbound-override/src/main/resources/verifying-jwk.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "keys": [ - { - "kty": "oct", - "kid": "helidon", - "alg": "HS256", - "key_ops": [ - "sign", - "verify" - ], - "k": "FdFYFzERwC2uCBB46pZQi4GG85LujR8obt-KWRBICVQ" - } - ] -} \ No newline at end of file diff --git a/examples/security/outbound-override/src/test/java/io/helidon/security/examples/outbound/OutboundOverrideExampleTest.java b/examples/security/outbound-override/src/test/java/io/helidon/security/examples/outbound/OutboundOverrideExampleTest.java deleted file mode 100644 index fabb17b179b..00000000000 --- a/examples/security/outbound-override/src/test/java/io/helidon/security/examples/outbound/OutboundOverrideExampleTest.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2020, 2024 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.security.examples.outbound; - -import java.net.URI; - -import io.helidon.security.EndpointConfig; -import io.helidon.security.Security; -import io.helidon.security.providers.httpauth.HttpBasicAuthProvider; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.security.WebClientSecurity; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - -/** - * Test of security override example. - */ -@ServerTest -public class OutboundOverrideExampleTest { - - private final Http1Client client; - - OutboundOverrideExampleTest(WebServer server, URI uri) { - server.context().register(server); - Security security = Security.builder() - .addProvider(HttpBasicAuthProvider.builder().build()) - .build(); - client = Http1Client.builder() - .baseUri(uri) - .addService(WebClientSecurity.create(security)) - .build(); - } - - @SetUpServer - public static void setup(WebServerConfig.Builder server) { - OutboundOverrideExample.setup(server); - } - - @Test - public void testOverrideExample() { - String value = client.get() - .path("/override") - .property(EndpointConfig.PROPERTY_OUTBOUND_ID, "jack") - .property(EndpointConfig.PROPERTY_OUTBOUND_SECRET, "changeit") - .requestEntity(String.class); - - assertThat(value, is("You are: jack, backend service returned: jill\n")); - } - - @Test - public void testPropagateExample() { - String value = client.get() - .path("/propagate") - .property(EndpointConfig.PROPERTY_OUTBOUND_ID, "jack") - .property(EndpointConfig.PROPERTY_OUTBOUND_SECRET, "changeit") - .requestEntity(String.class); - - assertThat(value, is("You are: jack, backend service returned: jack\n")); - } -} diff --git a/examples/security/outbound-override/src/test/java/io/helidon/security/examples/outbound/OutboundOverrideJwtExampleTest.java b/examples/security/outbound-override/src/test/java/io/helidon/security/examples/outbound/OutboundOverrideJwtExampleTest.java deleted file mode 100644 index d99934259de..00000000000 --- a/examples/security/outbound-override/src/test/java/io/helidon/security/examples/outbound/OutboundOverrideJwtExampleTest.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2021, 2024 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.security.examples.outbound; - -import java.net.URI; - -import io.helidon.security.EndpointConfig; -import io.helidon.security.Security; -import io.helidon.security.providers.httpauth.HttpBasicAuthProvider; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webclient.security.WebClientSecurity; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - -/** - * Test of security override example. - */ -@ServerTest -public class OutboundOverrideJwtExampleTest { - - private final Http1Client client; - - OutboundOverrideJwtExampleTest(WebServer server, URI uri) { - server.context().register(server); - Security security = Security.builder() - .addProvider(HttpBasicAuthProvider.builder().build()) - .build(); - client = Http1Client.builder() - .baseUri(uri) - .addService(WebClientSecurity.create(security)) - .build(); - } - - @SetUpServer - public static void setup(WebServerConfig.Builder server) { - OutboundOverrideJwtExample.setup(server); - } - - @Test - public void testOverrideExample() { - try (Http1ClientResponse response = client.get() - .path("/override") - .property(EndpointConfig.PROPERTY_OUTBOUND_ID, "jack") - .property(EndpointConfig.PROPERTY_OUTBOUND_SECRET, "changeit") - .request()) { - - assertThat(response.status().code(), is(200)); - - String entity = response.entity().as(String.class); - assertThat(entity, is("You are: jack, backend service returned: jill")); - } - } - - @Test - public void testPropagateExample() { - try (Http1ClientResponse response = client.get() - .path("/propagate") - .property(EndpointConfig.PROPERTY_OUTBOUND_ID, "jack") - .property(EndpointConfig.PROPERTY_OUTBOUND_SECRET, "changeit") - .request()) { - - assertThat(response.status().code(), is(200)); - - String entity = response.entity().as(String.class); - assertThat(entity, is("You are: jack, backend service returned: jack")); - } - - } -} diff --git a/examples/security/pom.xml b/examples/security/pom.xml deleted file mode 100644 index f86234ab009..00000000000 --- a/examples/security/pom.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples - helidon-examples-project - 4.1.0-SNAPSHOT - - io.helidon.examples.security - helidon-examples-security-project - Helidon Examples Security - pom - - - Examples of Helidon Security usage and integrations - - - - attribute-based-access-control - basic-auth-with-static-content - google-login - idcs-login - outbound-override - programmatic - spi-examples - vaults - webserver-digest-auth - webserver-signatures - - diff --git a/examples/security/programmatic/README.md b/examples/security/programmatic/README.md deleted file mode 100644 index cc9017e63bf..00000000000 --- a/examples/security/programmatic/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Helidon Security Example - -Example of manually using the security APIs. - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-security-nohttp-programmatic.jar -``` diff --git a/examples/security/programmatic/pom.xml b/examples/security/programmatic/pom.xml deleted file mode 100644 index 11e162583c8..00000000000 --- a/examples/security/programmatic/pom.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.security - helidon-examples-security-nohttp-programmatic - Helidon Examples Security No-HTTP programmatic - - - Example of programmatic security without an HTTP resource. - - - - io.helidon.examples.security.programmatic.ProgrammaticSecurity - - - - - io.helidon.security - helidon-security - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/security/programmatic/src/main/java/io/helidon/examples/security/programmatic/MyProvider.java b/examples/security/programmatic/src/main/java/io/helidon/examples/security/programmatic/MyProvider.java deleted file mode 100644 index 28ef5f5b0ed..00000000000 --- a/examples/security/programmatic/src/main/java/io/helidon/examples/security/programmatic/MyProvider.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.security.programmatic; - -import java.nio.charset.StandardCharsets; -import java.util.Base64; -import java.util.List; - -import io.helidon.security.AuthenticationResponse; -import io.helidon.security.AuthorizationResponse; -import io.helidon.security.EndpointConfig; -import io.helidon.security.OutboundSecurityResponse; -import io.helidon.security.Principal; -import io.helidon.security.ProviderRequest; -import io.helidon.security.Role; -import io.helidon.security.SecurityEnvironment; -import io.helidon.security.Subject; -import io.helidon.security.spi.AuthenticationProvider; -import io.helidon.security.spi.AuthorizationProvider; -import io.helidon.security.spi.OutboundSecurityProvider; - -/** - * Sample provider. - */ -class MyProvider implements AuthenticationProvider, AuthorizationProvider, OutboundSecurityProvider { - - @Override - public AuthenticationResponse authenticate(ProviderRequest providerRequest) { - //get username and password - List headers = providerRequest.env().headers().getOrDefault("authorization", List.of()); - if (headers.isEmpty()) { - return AuthenticationResponse.failed("No authorization header"); - } - - String header = headers.get(0); - if (header.toLowerCase().startsWith("basic ")) { - String base64 = header.substring(6); - String unamePwd = new String(Base64.getDecoder().decode(base64), StandardCharsets.UTF_8); - int index = unamePwd.indexOf(':'); - if (index > 0) { - String name = unamePwd.substring(0, index); - String pwd = unamePwd.substring(index + 1); - if ("aUser".equals(name)) { - //authenticate - Principal principal = Principal.create(name); - Role roleGrant = Role.create("theRole"); - - Subject subject = Subject.builder() - .principal(principal) - .addGrant(roleGrant) - .addPrivateCredential(MyPrivateCreds.class, new MyPrivateCreds(name, pwd.toCharArray())) - .build(); - - return AuthenticationResponse.success(subject); - } - } - } - - return AuthenticationResponse.failed("User not found"); - } - - @Override - public AuthorizationResponse authorize(ProviderRequest providerRequest) { - if ("CustomResourceType" - .equals(providerRequest.env().abacAttribute("resourceType").orElseThrow(() -> new IllegalArgumentException( - "Resource type is a required parameter")))) { - //supported resource - return providerRequest.securityContext() - .user() - .map(Subject::principal) - .map(Principal::getName) - .map("aUser"::equals) - .map(correct -> { - if (correct) { - return AuthorizationResponse.permit(); - } - return AuthorizationResponse.deny(); - }) - .orElse(AuthorizationResponse.deny()); - } - - return AuthorizationResponse.deny(); - } - - @Override - public OutboundSecurityResponse outboundSecurity(ProviderRequest providerRequest, - SecurityEnvironment outboundEnv, - EndpointConfig outboundEndpointConfig) { - - return providerRequest.securityContext() - .user() - .flatMap(subject -> subject.privateCredential(MyPrivateCreds.class)) - .map(myPrivateCreds -> OutboundSecurityResponse.builder() - .requestHeader("Authorization", authHeader(myPrivateCreds)) - .build() - ).orElse(OutboundSecurityResponse.abstain()); - } - - private String authHeader(MyPrivateCreds privCreds) { - String creds = privCreds.name + ":" + new String(privCreds.password); - return "basic " + Base64.getEncoder().encodeToString(creds.getBytes(StandardCharsets.UTF_8)); - } - - private static class MyPrivateCreds { - private final String name; - private final char[] password; - - private MyPrivateCreds(String name, char[] password) { - this.name = name; - this.password = password; - } - - @Override - public String toString() { - return "MyPrivateCreds: " + name; - } - } -} diff --git a/examples/security/programmatic/src/main/java/io/helidon/examples/security/programmatic/ProgrammaticSecurity.java b/examples/security/programmatic/src/main/java/io/helidon/examples/security/programmatic/ProgrammaticSecurity.java deleted file mode 100644 index 2fb76665dc3..00000000000 --- a/examples/security/programmatic/src/main/java/io/helidon/examples/security/programmatic/ProgrammaticSecurity.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2018, 2024 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.security.programmatic; - -import java.nio.charset.StandardCharsets; -import java.util.Base64; -import java.util.concurrent.ExecutionException; - -import io.helidon.security.AuthenticationResponse; -import io.helidon.security.AuthorizationResponse; -import io.helidon.security.OutboundSecurityResponse; -import io.helidon.security.Security; -import io.helidon.security.SecurityContext; -import io.helidon.security.Subject; - -/** - * This class shows how to manually secure your application. - */ -public class ProgrammaticSecurity { - private static final ThreadLocal CONTEXT = new ThreadLocal<>(); - private Security security; - - /** - * Entry point to this example. - * - * @param args no needed - * @throws ExecutionException if asynchronous security fails - * @throws InterruptedException if asynchronous security gets interrupted - */ - public static void main(String[] args) throws ExecutionException, InterruptedException { - ProgrammaticSecurity instance = new ProgrammaticSecurity(); - - /* - * Simple single threaded applications - nothing too complicated - */ - //1: initialize security component - instance.init(); - //2: login - Subject subject = instance.login(); - - //3: authorize access to restricted resource - instance.execute(); - //4: propagate identity - instance.propagate(); - - /* - * More complex - multithreaded application - */ - instance.multithreaded(subject); - - } - - private static String buildBasic(String user, String password) { - return "basic " + Base64.getEncoder() - .encodeToString((user + ":" + password).getBytes(StandardCharsets.UTF_8)); - } - - private void multithreaded(Subject subject) { - Thread thread = new Thread(() -> { - try { - SecurityContext context = security.contextBuilder("newThread") - .build(); - - CONTEXT.set(context); - - //this must be done, as there is no subject (yet) for current thread (or event the login attempt may be done - //in this thread - depends on what your application wants to do... - context.runAs(subject, () -> { - //3: authorize access to restricted resource - execute(); - //4: propagate identity - propagate(); - }); - } finally { - CONTEXT.remove(); - } - }); - thread.start(); - } - - private void propagate() { - OutboundSecurityResponse response = CONTEXT.get().outboundClientBuilder().buildAndGet(); - - switch (response.status()) { - case SUCCESS: - //we should have "Authorization" header present and just need to update request headers of our outbound call - System.out.println("Authorization header: " + response.requestHeaders().get("Authorization")); - break; - case SUCCESS_FINISH: - System.out.println("Identity propagation done, request sent..."); - break; - default: - System.out.println("Failed in identity propagation provider: " + response.description().orElse(null)); - break; - } - } - - private void execute() { - SecurityContext context = CONTEXT.get(); - //check role - if (!context.isUserInRole("theRole")) { - throw new IllegalStateException("User is not in expected role"); - } - - context.env(context.env() - .derive() - .addAttribute("resourceType", "CustomResourceType")); - - //check authorization through provider - AuthorizationResponse response = context.atzClientBuilder().buildAndGet(); - - if (response.status().isSuccess()) { - //ok, process resource - System.out.println("Resource processed"); - } else { - System.out.println("You are not permitted to process resource"); - } - } - - private Subject login() { - SecurityContext securityContext = CONTEXT.get(); - securityContext.env(securityContext.env().derive() - .path("/some/path") - .header("Authorization", buildBasic("aUser", "changeit"))); - - AuthenticationResponse response = securityContext.atnClientBuilder().buildAndGet(); - - if (response.status().isSuccess()) { - return response.user().orElseThrow(() -> new IllegalStateException("No user authenticated!")); - } - - throw new RuntimeException("Failed to authenticate", response.throwable().orElse(null)); - } - - private void init() { - //binds security context to current thread - this.security = Security.builder() - .addProvider(new MyProvider(), "FirstProvider") - .build(); - CONTEXT.set(security.contextBuilder("mainThread").build()); - } - -} diff --git a/examples/security/programmatic/src/main/java/io/helidon/examples/security/programmatic/package-info.java b/examples/security/programmatic/src/main/java/io/helidon/examples/security/programmatic/package-info.java deleted file mode 100644 index 0ed2a116082..00000000000 --- a/examples/security/programmatic/src/main/java/io/helidon/examples/security/programmatic/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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 of programmatic approach to security. - */ -package io.helidon.examples.security.programmatic; diff --git a/examples/security/programmatic/src/main/resources/logging.properties b/examples/security/programmatic/src/main/resources/logging.properties deleted file mode 100644 index 993d3d42d45..00000000000 --- a/examples/security/programmatic/src/main/resources/logging.properties +++ /dev/null @@ -1,19 +0,0 @@ -# -# Copyright (c) 2018, 2023 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. -# - -handlers=io.helidon.logging.jul.HelidonConsoleHandler -.level=INFO -AUDIT.level=FINEST diff --git a/examples/security/spi-examples/README.md b/examples/security/spi-examples/README.md deleted file mode 100644 index 15652fc7aa4..00000000000 --- a/examples/security/spi-examples/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# SPI implementation - -This example demonstrates how to implement various SPIs of security component. - -Contents --------- -The following examples are available: -1. Authentication provider -2. Authorization provider -3. Outbound provider -3. Audit provider -4. Provider selection policy - -# Running the Example - -This is an API/SPI example. It is validated through unit tests. - \ No newline at end of file diff --git a/examples/security/spi-examples/pom.xml b/examples/security/spi-examples/pom.xml deleted file mode 100644 index 4d4f5495a16..00000000000 --- a/examples/security/spi-examples/pom.xml +++ /dev/null @@ -1,82 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.security - helidon-examples-security-spi - Helidon Examples Security SPI Implementation - - - Example of implementation of custom providers and other SPI implementations - - - - 2.23.4 - - - - - io.helidon.security - helidon-security - - - io.helidon.bundles - helidon-bundles-config - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-core - test - - - org.mockito - mockito-core - ${version.lib.mockito} - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/AtnProviderImpl.java b/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/AtnProviderImpl.java deleted file mode 100644 index 4c542e7318c..00000000000 --- a/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/AtnProviderImpl.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.security.examples.spi; - -import java.lang.annotation.Annotation; -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Optional; -import java.util.Set; - -import io.helidon.common.config.Config; -import io.helidon.security.AuthenticationResponse; -import io.helidon.security.EndpointConfig; -import io.helidon.security.Principal; -import io.helidon.security.ProviderRequest; -import io.helidon.security.Role; -import io.helidon.security.SecurityLevel; -import io.helidon.security.Subject; -import io.helidon.security.spi.AuthenticationProvider; - -/** - * Example of an authentication provider implementation. - * This is a full-blown example of a provider that requires additional configuration on a resource. - */ -public class AtnProviderImpl implements AuthenticationProvider { - @Override - public AuthenticationResponse authenticate(ProviderRequest providerRequest) { - - // first obtain the configuration of this request - // either from annotation, custom object or config - AtnObject myObject = getCustomObject(providerRequest.endpointConfig()); - - if (null == myObject) { - // I do not have my required information, this request is probably not for me - return AuthenticationResponse.abstain(); - } - - if (myObject.isValid()) { - // now authenticate - this example just creates a subject - // based on the value (user subject) and size (group subject) - return AuthenticationResponse.success(Subject.builder() - .addPrincipal(Principal.create(myObject.getValue())) - .addGrant(Role.create("role_" + myObject.getSize())) - .build()); - } else { - return AuthenticationResponse.failed("Invalid request"); - } - } - - private AtnObject getCustomObject(EndpointConfig epConfig) { - // order I choose - this depends on type of security you implement and your choice: - // 1) custom object in request (as this must be explicitly done by a developer) - Optional opt = epConfig.instance(AtnObject.class); - if (opt.isPresent()) { - return opt.get(); - } - - // 2) configuration in request - opt = epConfig.config("atn-object").flatMap(conf -> conf.map(AtnObject::from).asOptional()); - if (opt.isPresent()) { - return opt.get(); - } - - // 3) annotations on target - List annots = new ArrayList<>(); - for (SecurityLevel securityLevel : epConfig.securityLevels()) { - annots.addAll(securityLevel.combineAnnotations(AtnAnnot.class, EndpointConfig.AnnotationScope.values())); - } - if (annots.isEmpty()) { - return null; - } else { - return AtnObject.from(annots.get(0)); - } - } - - @Override - public Collection> supportedAnnotations() { - return Set.of(AtnAnnot.class); - } - - /** - * This is an example annotation to see how to work with them. - */ - @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.METHOD, ElementType.TYPE, ElementType.FIELD}) - @Documented - public @interface AtnAnnot { - /** - * This is an example value. - * - * @return some value - */ - String value(); - - /** - * This is an example value. - * - * @return some size - */ - int size() default 4; - } - - /** - * This is an example custom object. - * Also acts as an object to get configuration in config. - */ - public static class AtnObject { - private String value; - private int size = 4; - - /** - * Load this object instance from configuration. - * - * @param config configuration - * @return a new instance - */ - public static AtnObject from(Config config) { - AtnObject result = new AtnObject(); - config.get("value").asString().ifPresent(result::setValue); - config.get("size").asInt().ifPresent(result::setSize); - return result; - } - - static AtnObject from(AtnAnnot annot) { - AtnObject result = new AtnObject(); - result.setValue(annot.value()); - result.setSize(annot.size()); - return result; - } - - static AtnObject from(String value, int size) { - AtnObject result = new AtnObject(); - result.setValue(value); - result.setSize(size); - return result; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - public int getSize() { - return size; - } - - public void setSize(int size) { - this.size = size; - } - - public boolean isValid() { - return null != value; - } - } -} diff --git a/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/AtzProviderSync.java b/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/AtzProviderSync.java deleted file mode 100644 index 6570ee6e271..00000000000 --- a/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/AtzProviderSync.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.security.examples.spi; - -import io.helidon.security.AuthorizationResponse; -import io.helidon.security.ProviderRequest; -import io.helidon.security.spi.AuthorizationProvider; - -/** - * Authorization provider example. The most simplistic approach. - * - * @see AtnProviderImpl on how to use custom objects, config and annotations in a provider - */ -public class AtzProviderSync implements AuthorizationProvider { - @Override - public AuthorizationResponse authorize(ProviderRequest providerRequest) { - // just check the path contains the string "public", otherwise allow only if user is logged in - // if no path is defined, abstain (e.g. I do not care about such requests - I can neither allow or deny them) - return providerRequest.env().path() - .map(path -> { - if (path.contains("public")) { - return AuthorizationResponse.permit(); - } - if (providerRequest.securityContext().isAuthenticated()) { - return AuthorizationResponse.permit(); - } else { - return AuthorizationResponse.deny(); - } - }).orElse(AuthorizationResponse.abstain()); - } -} diff --git a/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/Auditer.java b/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/Auditer.java deleted file mode 100644 index d5f0fc261a4..00000000000 --- a/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/Auditer.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2018, 2021 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.security.examples.spi; - -import java.util.LinkedList; -import java.util.List; -import java.util.function.Consumer; - -import io.helidon.security.spi.AuditProvider; - -/** - * Audit provider implementation. - */ -public class Auditer implements AuditProvider { - // BEWARE this is a memory leak. Only for example purposes and for unit-tests - private final List messages = new LinkedList<>(); - - public List getMessages() { - return messages; - } - - @Override - public Consumer auditConsumer() { - return event -> { - // just dump to stdout and store in a list - System.out.println(event.severity() + ": " + event.tracingId() + ": " + event); - messages.add(event); - }; - } - -} diff --git a/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/OutboundProviderSync.java b/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/OutboundProviderSync.java deleted file mode 100644 index f7217d4d69b..00000000000 --- a/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/OutboundProviderSync.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.security.examples.spi; - -import java.util.List; -import java.util.Map; - -import io.helidon.security.EndpointConfig; -import io.helidon.security.OutboundSecurityResponse; -import io.helidon.security.Principal; -import io.helidon.security.ProviderRequest; -import io.helidon.security.SecurityEnvironment; -import io.helidon.security.Subject; -import io.helidon.security.spi.OutboundSecurityProvider; - -/** - * Example of a simplistic outbound security provider. - */ -public class OutboundProviderSync implements OutboundSecurityProvider { - @Override - public OutboundSecurityResponse outboundSecurity(ProviderRequest providerRequest, - SecurityEnvironment outboundEnv, - EndpointConfig outboundEndpointConfig) { - - // let's just add current user's id as a custom header, otherwise do nothing - return providerRequest.securityContext() - .user() - .map(Subject::principal) - .map(Principal::getName) - .map(name -> OutboundSecurityResponse - .withHeaders(Map.of("X-AUTH-USER", List.of(name)))) - .orElse(OutboundSecurityResponse.abstain()); - } -} diff --git a/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/ProviderSelector.java b/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/ProviderSelector.java deleted file mode 100644 index 7c26e04d9e1..00000000000 --- a/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/ProviderSelector.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2018, 2021 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.security.examples.spi; - -import java.util.LinkedList; -import java.util.List; -import java.util.Optional; - -import io.helidon.security.NamedProvider; -import io.helidon.security.spi.OutboundSecurityProvider; -import io.helidon.security.spi.ProviderSelectionPolicy; -import io.helidon.security.spi.SecurityProvider; - -/** - * Simple selector of providers, just chooses first, except for outbound, where it returns all. - */ -public class ProviderSelector implements ProviderSelectionPolicy { - private final Providers providers; - private final List outboundProviders = new LinkedList<>(); - - private ProviderSelector(Providers providers) { - this.providers = providers; - - providers.getProviders(OutboundSecurityProvider.class) - .forEach(np -> outboundProviders.add(np.getProvider())); - } - - /** - * This is the function to register with security. - * - * @param providers Providers from security - * @return selector instance - * @see io.helidon.security.Security.Builder#providerSelectionPolicy(java.util.function.Function) - */ - public static ProviderSelector create(Providers providers) { - return new ProviderSelector(providers); - } - - @Override - public Optional selectProvider(Class providerType) { - List> providers = this.providers.getProviders(providerType); - - if (providers.isEmpty()) { - return Optional.empty(); - } else { - return Optional.of(providers.get(0).getProvider()); - } - } - - @Override - public List selectOutboundProviders() { - return outboundProviders; - } - - @Override - public Optional selectProvider(Class providerType, String requestedName) { - return this.providers.getProviders(providerType) - .stream() - .filter(provider -> provider.getName().equals(requestedName)) - .findFirst() - .map(NamedProvider::getProvider); - } -} diff --git a/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/package-info.java b/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/package-info.java deleted file mode 100644 index c7ac4119d87..00000000000 --- a/examples/security/spi-examples/src/main/java/io/helidon/security/examples/spi/package-info.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2018, 2021 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. - */ - -/** - * Examples of SPI implementation. - * - * @see io.helidon.security.spi.AuthenticationProvider - */ -package io.helidon.security.examples.spi; diff --git a/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/AtnProviderSyncTest.java b/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/AtnProviderSyncTest.java deleted file mode 100644 index 93760459ec3..00000000000 --- a/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/AtnProviderSyncTest.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.security.examples.spi; - -import java.lang.annotation.Annotation; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.security.AuthenticationResponse; -import io.helidon.security.EndpointConfig; -import io.helidon.security.ProviderRequest; -import io.helidon.security.Security; -import io.helidon.security.SecurityContext; -import io.helidon.security.SecurityEnvironment; -import io.helidon.security.SecurityLevel; -import io.helidon.security.SecurityResponse; -import io.helidon.security.Subject; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.fail; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * Unit test for {@link AtnProviderImpl}. - */ -public class AtnProviderSyncTest { - private static final String VALUE = "aValue"; - private static final int SIZE = 16; - - @Test - public void testAbstain() { - SecurityContext context = mock(SecurityContext.class); - when(context.user()).thenReturn(Optional.empty()); - when(context.service()).thenReturn(Optional.empty()); - - SecurityEnvironment se = SecurityEnvironment.create(); - EndpointConfig ep = EndpointConfig.create(); - - ProviderRequest request = mock(ProviderRequest.class); - when(request.securityContext()).thenReturn(context); - when(request.env()).thenReturn(se); - when(request.endpointConfig()).thenReturn(ep); - - AtnProviderImpl provider = new AtnProviderImpl(); - - AuthenticationResponse response = provider.authenticate(request); - - assertThat(response.status(), is(SecurityResponse.SecurityStatus.ABSTAIN)); - } - - @Test - public void testAnnotationSuccess() { - AtnProviderImpl.AtnAnnot annot = new AtnProviderImpl.AtnAnnot() { - @Override - public String value() { - return VALUE; - } - - @Override - public int size() { - return SIZE; - } - - @Override - public Class annotationType() { - return AtnProviderImpl.AtnAnnot.class; - } - }; - - SecurityContext context = mock(SecurityContext.class); - when(context.user()).thenReturn(Optional.empty()); - when(context.service()).thenReturn(Optional.empty()); - - SecurityEnvironment se = SecurityEnvironment.create(); - - SecurityLevel level = SecurityLevel.create("mock") - .withClassAnnotations(Map.of(AtnProviderImpl.AtnAnnot.class, List.of(annot))) - .build(); - - EndpointConfig ep = EndpointConfig.builder() - .securityLevels(List.of(level)) - .build(); - - ProviderRequest request = mock(ProviderRequest.class); - when(request.securityContext()).thenReturn(context); - when(request.env()).thenReturn(se); - when(request.endpointConfig()).thenReturn(ep); - - testSuccess(request); - } - - @Test - public void testCustomObjectSuccess() { - AtnProviderImpl.AtnObject obj = new AtnProviderImpl.AtnObject(); - obj.setSize(SIZE); - obj.setValue(VALUE); - - SecurityContext context = mock(SecurityContext.class); - when(context.user()).thenReturn(Optional.empty()); - when(context.service()).thenReturn(Optional.empty()); - - SecurityEnvironment se = SecurityEnvironment.create(); - EndpointConfig ep = EndpointConfig.builder() - .customObject(AtnProviderImpl.AtnObject.class, obj) - .build(); - - ProviderRequest request = mock(ProviderRequest.class); - when(request.securityContext()).thenReturn(context); - when(request.env()).thenReturn(se); - when(request.endpointConfig()).thenReturn(ep); - - testSuccess(request); - } - - @Test - public void testConfigSuccess() { - Config config = Config.create( - ConfigSources.create(Map.of("value", VALUE, - "size", String.valueOf(SIZE))) - ); - - SecurityContext context = mock(SecurityContext.class); - when(context.user()).thenReturn(Optional.empty()); - when(context.service()).thenReturn(Optional.empty()); - - SecurityEnvironment se = SecurityEnvironment.create(); - EndpointConfig ep = EndpointConfig.builder() - .config("atn-object", config) - .build(); - - ProviderRequest request = mock(ProviderRequest.class); - when(request.securityContext()).thenReturn(context); - when(request.env()).thenReturn(se); - when(request.endpointConfig()).thenReturn(ep); - - - testSuccess(request); - } - - @Test - public void testFailure() { - Config config = Config.create( - ConfigSources.create(Map.of("atn-object.size", String.valueOf(SIZE))) - ); - - SecurityContext context = mock(SecurityContext.class); - when(context.user()).thenReturn(Optional.empty()); - when(context.service()).thenReturn(Optional.empty()); - - SecurityEnvironment se = SecurityEnvironment.create(); - EndpointConfig ep = EndpointConfig.builder() - .config("atn-object", config) - .build(); - - ProviderRequest request = mock(ProviderRequest.class); - when(request.securityContext()).thenReturn(context); - when(request.env()).thenReturn(se); - when(request.endpointConfig()).thenReturn(ep); - - AtnProviderImpl provider = new AtnProviderImpl(); - - AuthenticationResponse response = provider.authenticate(request); - - assertThat(response.status(), is(SecurityResponse.SecurityStatus.FAILURE)); - } - - @Test - public void integrationTest() { - Security security = Security.builder() - .addProvider(new AtnProviderImpl()) - .build(); - - // this part is usually done by container integration component - // in Jersey you have access to security context through annotations - // in Web server you have access to security context through context - SecurityContext context = security.createContext("unit-test"); - context.endpointConfig(EndpointConfig.builder() - .customObject(AtnProviderImpl.AtnObject.class, - AtnProviderImpl.AtnObject.from(VALUE, SIZE))); - AuthenticationResponse response = context.authenticate(); - - validateResponse(response); - } - - private void validateResponse(AuthenticationResponse response) { - assertThat(response.status(), is(SecurityResponse.SecurityStatus.SUCCESS)); - Optional maybeuser = response.user(); - - maybeuser.ifPresentOrElse(user -> { - assertThat(user.principal().id(), is(VALUE)); - Set roles = Security.getRoles(user); - assertThat(roles.size(), is(1)); - assertThat(roles.iterator().next(), is("role_" + SIZE)); - }, () -> fail("User should have been returned")); - } - - private void testSuccess(ProviderRequest request) { - AtnProviderImpl provider = new AtnProviderImpl(); - - AuthenticationResponse response = provider.authenticate(request); - validateResponse(response); - } -} diff --git a/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/AtzProviderSyncTest.java b/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/AtzProviderSyncTest.java deleted file mode 100644 index 340d68caeca..00000000000 --- a/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/AtzProviderSyncTest.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.security.examples.spi; - -import io.helidon.security.AuthorizationResponse; -import io.helidon.security.EndpointConfig; -import io.helidon.security.ProviderRequest; -import io.helidon.security.SecurityContext; -import io.helidon.security.SecurityEnvironment; -import io.helidon.security.SecurityResponse; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * Unit test for {@link AtzProviderSync}. - */ -public class AtzProviderSyncTest { - @Test - public void testPublic() { - SecurityEnvironment se = SecurityEnvironment.builder() - .path("/public/some/path") - .build(); - EndpointConfig ep = EndpointConfig.create(); - - ProviderRequest request = mock(ProviderRequest.class); - when(request.env()).thenReturn(se); - when(request.endpointConfig()).thenReturn(ep); - - AtzProviderSync provider = new AtzProviderSync(); - - AuthorizationResponse response = provider.authorize(request); - - assertThat(response.status(), is(SecurityResponse.SecurityStatus.SUCCESS)); - } - - @Test - public void testAbstain() { - SecurityEnvironment se = SecurityEnvironment.create(); - EndpointConfig ep = EndpointConfig.create(); - - ProviderRequest request = mock(ProviderRequest.class); - when(request.env()).thenReturn(se); - when(request.endpointConfig()).thenReturn(ep); - - AtzProviderSync provider = new AtzProviderSync(); - - AuthorizationResponse response = provider.authorize(request); - - assertThat(response.status(), is(SecurityResponse.SecurityStatus.ABSTAIN)); - } - - @Test - public void testDenied() { - SecurityContext context = mock(SecurityContext.class); - when(context.isAuthenticated()).thenReturn(false); - - SecurityEnvironment se = SecurityEnvironment.builder() - .path("/private/some/path") - .build(); - EndpointConfig ep = EndpointConfig.create(); - - ProviderRequest request = mock(ProviderRequest.class); - when(request.securityContext()).thenReturn(context); - when(request.env()).thenReturn(se); - when(request.endpointConfig()).thenReturn(ep); - - AtzProviderSync provider = new AtzProviderSync(); - - AuthorizationResponse response = provider.authorize(request); - - assertThat(response.status(), is(SecurityResponse.SecurityStatus.FAILURE)); - } - - @Test - public void testPermitted() { - SecurityContext context = mock(SecurityContext.class); - when(context.isAuthenticated()).thenReturn(true); - - SecurityEnvironment se = SecurityEnvironment.builder() - .path("/private/some/path") - .build(); - EndpointConfig ep = EndpointConfig.create(); - - ProviderRequest request = mock(ProviderRequest.class); - when(request.securityContext()).thenReturn(context); - when(request.env()).thenReturn(se); - when(request.endpointConfig()).thenReturn(ep); - - AtzProviderSync provider = new AtzProviderSync(); - - AuthorizationResponse response = provider.authorize(request); - - assertThat(response.status(), is(SecurityResponse.SecurityStatus.SUCCESS)); - } -} diff --git a/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/AuditerTest.java b/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/AuditerTest.java deleted file mode 100644 index 8ff42efbef8..00000000000 --- a/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/AuditerTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2018, 2021 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.security.examples.spi; - -import java.util.List; -import java.util.stream.Collectors; - -import io.helidon.security.AuditEvent; -import io.helidon.security.AuthorizationResponse; -import io.helidon.security.Security; -import io.helidon.security.SecurityContext; -import io.helidon.security.SecurityEnvironment; -import io.helidon.security.spi.AuditProvider; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Unit test for {@link Auditer}. - */ -public class AuditerTest { - @Test - public void integrateIt() throws InterruptedException { - Auditer auditer = new Auditer(); - - Security sec = Security.builder() - .addAuthorizationProvider(new AtzProviderSync()) - .addAuditProvider(auditer) - .build(); - - SecurityContext context = sec.createContext("unit-test"); - context.env(SecurityEnvironment.builder() - .path("/public/path")); - - AuthorizationResponse response = context.authorize(); - - // as auditing is asynchronous, we must give it some time to process - Thread.sleep(100); - - List messages = auditer.getMessages(); - // there should be two messages - configuration of security and authorization - - List atzEvents = messages.stream() - .filter(event -> event.eventType().startsWith(AuditEvent.AUTHZ_TYPE_PREFIX)) - .collect(Collectors.toList()); - - assertThat("We only expect a single authorization event", atzEvents.size(), is(1)); - - } -} diff --git a/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/OutboundProviderSyncTest.java b/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/OutboundProviderSyncTest.java deleted file mode 100644 index e2dfa640fed..00000000000 --- a/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/OutboundProviderSyncTest.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.security.examples.spi; - -import java.util.List; -import java.util.Optional; - -import io.helidon.security.EndpointConfig; -import io.helidon.security.OutboundSecurityResponse; -import io.helidon.security.Principal; -import io.helidon.security.ProviderRequest; -import io.helidon.security.SecurityContext; -import io.helidon.security.SecurityEnvironment; -import io.helidon.security.SecurityResponse; -import io.helidon.security.Subject; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * Unit test for {@link OutboundProviderSync}. - */ -public class OutboundProviderSyncTest { - @Test - public void testAbstain() { - SecurityContext context = mock(SecurityContext.class); - when(context.user()).thenReturn(Optional.empty()); - when(context.service()).thenReturn(Optional.empty()); - - SecurityEnvironment se = SecurityEnvironment.create(); - - ProviderRequest request = mock(ProviderRequest.class); - when(request.securityContext()).thenReturn(context); - when(request.env()).thenReturn(se); - - OutboundProviderSync ops = new OutboundProviderSync(); - OutboundSecurityResponse response = ops.outboundSecurity(request, SecurityEnvironment.create(), EndpointConfig.create()); - - assertThat(response.status(), is(SecurityResponse.SecurityStatus.ABSTAIN)); - } - - @Test - public void testSuccess() { - String username = "aUser"; - Subject subject = Subject.create(Principal.create(username)); - - SecurityContext context = mock(SecurityContext.class); - when(context.user()).thenReturn(Optional.of(subject)); - when(context.service()).thenReturn(Optional.empty()); - - SecurityEnvironment se = SecurityEnvironment.create(); - - ProviderRequest request = mock(ProviderRequest.class); - when(request.securityContext()).thenReturn(context); - when(request.env()).thenReturn(se); - - OutboundProviderSync ops = new OutboundProviderSync(); - OutboundSecurityResponse response = ops.outboundSecurity(request, SecurityEnvironment.create(), EndpointConfig.create()); - - assertThat(response.status(), is(SecurityResponse.SecurityStatus.SUCCESS)); - assertThat(response.requestHeaders().get("X-AUTH-USER"), is(List.of(username))); - } -} diff --git a/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/ProviderSelectorTest.java b/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/ProviderSelectorTest.java deleted file mode 100644 index c076ef8090d..00000000000 --- a/examples/security/spi-examples/src/test/java/io/helidon/security/examples/spi/ProviderSelectorTest.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.security.examples.spi; - -import io.helidon.security.AuthorizationResponse; -import io.helidon.security.Security; -import io.helidon.security.SecurityContext; -import io.helidon.security.SecurityEnvironment; - -import org.junit.jupiter.api.Test; - -/** - * Unit test for {@link ProviderSelector}. - */ -public class ProviderSelectorTest { - @Test - public void integrateIt() { - Security security = Security.builder() - .providerSelectionPolicy(ProviderSelector::create) - .addProvider(new AtnProviderImpl()) - .addProvider(new AtzProviderSync()) - .build(); - - SecurityContext context = security.createContext("unit-test"); - context.env(SecurityEnvironment.builder().path("/public/path")); - - AuthorizationResponse response = context.authorize(); - - // if we reached here, the policy worked - } -} diff --git a/examples/security/vaults/README.md b/examples/security/vaults/README.md deleted file mode 100644 index 6ee954528ca..00000000000 --- a/examples/security/vaults/README.md +++ /dev/null @@ -1,34 +0,0 @@ -Vaults example ----- - -This example demonstrates the use of `Security` to: -- access secrets -- generate digests (such as Signatures and HMAC) -- verify digests (dtto) -- encrypt secret text -- decrypt cipher text - -The example uses three implementations of security providers that implement these features: - -1. OCI Vault provider (supports all) -2. Config provider (supports encryption/decryption and secrets) -3. Hashicorp (HCP) Vault provider (supports all + HMAC digest) - - -# OCI Vault - -The following information/configuration is needed: - -1. `~/.oci/config` file should be present (TODO link to description how to get it) -2. A secret (for password) must be created and its OCID configured in `${oci.properties.secret-ocid}` -3. An RSA key must be created and its OCID configured in `${oci.properties.vault-rsa-key-ocid}` for signature -4. Key must be created and its OCID configured in `${oci.properties.vault-key-ocid}` for encryption - -# HCP Vault - -1. Vault address must be defined in `vault.address` -2. Vault token must be defined in `vault.token` -3. A secret must be defined in the default secrets under path `app/secret` with key `username` defining a user -4. Vault `transit` secret engine must be enabled -5. A key named `signature-key` must be created (RSA) in `transit` secret engine for signature -6. A key named `encryption-key` must be created in `transit` secret engine for encryption and HMAC diff --git a/examples/security/vaults/pom.xml b/examples/security/vaults/pom.xml deleted file mode 100644 index 0590c02b0ec..00000000000 --- a/examples/security/vaults/pom.xml +++ /dev/null @@ -1,104 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.security - helidon-examples-security-vaults - Helidon Examples Security Vaults - - - This example demonstrates usage of vault implementations - OCI, Hashicorp Vault, and Config based vault - - - - io.helidon.examples.security.vaults.VaultsExampleMain - - - - - io.helidon.config - helidon-config - - - io.helidon.config - helidon-config-yaml - - - io.helidon.config - helidon-config-encryption - - - io.helidon.security - helidon-security - - - io.helidon.security.providers - helidon-security-providers-config-vault - - - io.helidon.webserver - helidon-webserver - - - io.helidon.integrations.vault.secrets - helidon-integrations-vault-secrets-kv2 - - - io.helidon.integrations.vault.secrets - helidon-integrations-vault-secrets-transit - - - io.helidon.integrations.vault.auths - helidon-integrations-vault-auths-token - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-core - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/DigestService.java b/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/DigestService.java deleted file mode 100644 index 1aad96caf01..00000000000 --- a/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/DigestService.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.security.vaults; - -import io.helidon.security.Security; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -import static java.nio.charset.StandardCharsets.UTF_8; - -class DigestService implements HttpService { - private final Security security; - - DigestService(Security security) { - this.security = security; - } - - - @Override - public void routing(HttpRules rules) { - rules.get("/digest/{config}/{text}", this::digest) - .get("/verify/{config}/{text}/{digest:.*}", this::verify); - } - - private void digest(ServerRequest req, ServerResponse res) { - String configName = req.path().pathParameters().get("config"); - String text = req.path().pathParameters().get("text"); - - res.send(security.digest(configName, text.getBytes(UTF_8))); - } - - private void verify(ServerRequest req, ServerResponse res) { - String configName = req.path().pathParameters().get("config"); - String text = req.path().pathParameters().get("text"); - String digest = req.path().pathParameters().get("digest"); - - boolean valid = security.verifyDigest(configName, text.getBytes(UTF_8), digest); - res.send(valid ? "Valid" : "Invalid"); - } -} diff --git a/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/EncryptionService.java b/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/EncryptionService.java deleted file mode 100644 index 52faeb1955e..00000000000 --- a/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/EncryptionService.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.security.vaults; - -import io.helidon.security.Security; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -import static java.nio.charset.StandardCharsets.UTF_8; - -class EncryptionService implements HttpService { - private final Security security; - - EncryptionService(Security security) { - this.security = security; - } - - - @Override - public void routing(HttpRules rules) { - rules.get("/encrypt/{config}/{text:.*}", this::encrypt) - .get("/decrypt/{config}/{cipherText:.*}", this::decrypt); - } - - private void encrypt(ServerRequest req, ServerResponse res) { - String configName = req.path().pathParameters().get("config"); - String text = req.path().pathParameters().get("text"); - - res.send(security.encrypt(configName, text.getBytes(UTF_8))); - } - - private void decrypt(ServerRequest req, ServerResponse res) { - String configName = req.path().pathParameters().get("config"); - String cipherText = req.path().pathParameters().get("cipherText"); - - res.send(security.decrypt(configName, cipherText)); - } -} diff --git a/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/SecretsService.java b/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/SecretsService.java deleted file mode 100644 index fdc566c4964..00000000000 --- a/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/SecretsService.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.security.vaults; - -import io.helidon.security.Security; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -class SecretsService implements HttpService { - private final Security security; - - SecretsService(Security security) { - this.security = security; - } - - - @Override - public void routing(HttpRules rules) { - rules.get("/{name}", this::secret); - } - - private void secret(ServerRequest req, ServerResponse res) { - String secretName = req.path().pathParameters().get("name"); - res.send(security.secret(secretName, "default-" + secretName)); - } -} diff --git a/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/VaultsExampleMain.java b/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/VaultsExampleMain.java deleted file mode 100644 index 315954f7d5c..00000000000 --- a/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/VaultsExampleMain.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.security.vaults; - -import io.helidon.config.Config; -import io.helidon.logging.common.LogConfig; -import io.helidon.security.Security; -import io.helidon.webserver.WebServer; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.file; - -/** - * Main class of the example based on configuration. - */ -public final class VaultsExampleMain { - private VaultsExampleMain() { - } - - /** - * Start the server. - * - * @param args ignored - */ - public static void main(String[] args) { - LogConfig.configureRuntime(); - - // as I cannot share my configuration of OCI, let's combine the configuration - // from my home directory with the one compiled into the jar - // when running this example, you can either update the application.yaml in resources directory - // or use the same approach - Config config = buildConfig(); - - System.out.println("This example requires a valid OCI Vault, Secret and keys configured. It also requires " - + "a Hashicorp Vault running with preconfigured data. Please see README.md"); - - Security security = Security.create(config.get("security")); - - WebServer server = WebServer.builder() - .config(config.get("server")) - .routing(routing -> routing - .register("/secrets", new SecretsService(security)) - .register("/encryption", new EncryptionService(security)) - .register("/digests", new DigestService(security))) - .build() - .start(); - - System.out.println("Server started on port: " + server.port()); - String baseAddress = "http://localhost:" + server.port() + "/"; - - System.out.println("Secrets endpoints:"); - System.out.println(); - System.out.println("OCI secret:"); - System.out.println("\t" + baseAddress + "secrets/password"); - System.out.println("Config secret:"); - System.out.println("\t" + baseAddress + "secrets/token"); - System.out.println("HCP Vault secret:"); - System.out.println("\t" + baseAddress + "secrets/username"); - System.out.println(); - - System.out.println("Encryption endpoints:"); - System.out.println("OCI encrypted:"); - System.out.println("\t" + baseAddress + "encryption/encrypt/crypto-1/text"); - System.out.println("\t" + baseAddress + "encryption/decrypt/crypto-1/cipherText"); - System.out.println("Config encrypted:"); - System.out.println("\t" + baseAddress + "encryption/encrypt/crypto-2/text"); - System.out.println("\t" + baseAddress + "encryption/decrypt/crypto-2/cipherText"); - System.out.println("HCP Vault encrypted:"); - System.out.println("\t" + baseAddress + "encryption/encrypt/crypto-3/text"); - System.out.println("\t" + baseAddress + "encryption/decrypt/crypto-3/cipherText"); - System.out.println(); - - System.out.println("Signature/HMAC endpoints:"); - System.out.println("OCI Signature:"); - System.out.println("\t" + baseAddress + "digests/digest/sig-1/text"); - System.out.println("\t" + baseAddress + "digests/verify/sig-1/text/signature"); - System.out.println("HCP Vault Signature:"); - System.out.println("\t" + baseAddress + "digests/digest/sig-2/text"); - System.out.println("\t" + baseAddress + "digests/digest/sig-2/text/signature"); - System.out.println("HCP Vault HMAC:"); - System.out.println("\t" + baseAddress + "digests/digest/hmac-1/text"); - System.out.println("\t" + baseAddress + "digests/digest/hmac-2/text/hmac"); - } - - private static Config buildConfig() { - return Config.builder() - .sources( - // you can use this file to override the defaults that are built-in - file(System.getProperty("user.home") + "/helidon/conf/examples.yaml").optional(), - // in jar file (see src/main/resources/application.yaml) - classpath("application.yaml")) - .build(); - } -} diff --git a/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/package-info.java b/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/package-info.java deleted file mode 100644 index 4496d133304..00000000000 --- a/examples/security/vaults/src/main/java/io/helidon/examples/security/vaults/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2021 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 of basic vault operations available in {@link io.helidon.security.Security}. - */ -package io.helidon.examples.security.vaults; diff --git a/examples/security/vaults/src/main/resources/application.yaml b/examples/security/vaults/src/main/resources/application.yaml deleted file mode 100644 index 30fb258b198..00000000000 --- a/examples/security/vaults/src/main/resources/application.yaml +++ /dev/null @@ -1,92 +0,0 @@ -# -# Copyright (c) 2021, 2024 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. -# - -# -# All Hashicorp Vault configuration is commented out, as this PR only handles OCI -# This should be added in HCP Vault PR -# - -server: - port: 8080 - -app.token: "argb-urgx-harsps" - -vault: - token: "myroot" - address: "http://localhost:8200" - -security: - providers: - - config-vault: - master-password: "very much secret" - - vault-kv2: - address: "${vault.address}" - token: "${vault.token}" - - vault-transit: - address: "${vault.address}" - token: "${vault.token}" - # - oci-vault: - # We need either the cryptographic endpoint (recommended), or management-endpoint configured - # Also ~/.oci/config must be correctly set up, otherwise all information is required here - # The crypto endpoint may be configured per digest/encryption, as we may use more than one - # vault in a single application - # vault.cryptographic-endpoint: "${oci.properties.cryptographic-endpoint}" - # vault.management-endpoint: "${oci.properties.management-endpoint}" - secrets: - - name: "username" - provider: "vault-kv2" - config: - path: "app/secret" - key: "username" -# - name: "changeit" -# provider: "oci-vault" -# config: -# ocid: "${oci.properties.secret-ocid}" - - name: "token" - provider: "config-vault" - config: - value: "${app.token}" - digest: - # Signatures and hmac - - name: "sig-2" - provider: "vault-transit" - config: - type: "signature" - key-name: "signature-key" - - name: "hmac-1" - provider: "vault-transit" - config: - type: "hmac" - key-name: "encryption-key" -# - name: "sig-1" -# provider: "oci-vault" -# config: -# cryptographic-endpoint: "${oci.properties.cryptographic-endpoint}" -# key-ocid: "${oci.properties.vault-rsa-key-ocid}" -# algorithm: "SHA_256_RSA_PKCS_PSS" - encryption: - # encryption and decryption - - name: "crypto-3" - provider: "vault-transit" - config: - key-name: "encryption-key" -# - name: "crypto-1" -# provider: "oci-vault" -# config: -# cryptographic-endpoint: "${oci.properties.cryptographic-endpoint}" -# key-ocid: "${oci.properties.vault-key-ocid}" - - name: "crypto-2" - provider: "config-vault" diff --git a/examples/security/vaults/src/main/resources/logging.properties b/examples/security/vaults/src/main/resources/logging.properties deleted file mode 100644 index f8802f90626..00000000000 --- a/examples/security/vaults/src/main/resources/logging.properties +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright (c) 2021, 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. -# - -# Send messages to the console -handlers=io.helidon.logging.jul.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 - -io.helidon.level=INFO -io.helidon.integrations.level=INFO diff --git a/examples/security/webserver-digest-auth/README.md b/examples/security/webserver-digest-auth/README.md deleted file mode 100644 index bc9628e8749..00000000000 --- a/examples/security/webserver-digest-auth/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# Web Server Integration and Digest Authentication - -This example demonstrates Integration of WebServer -based application with Security component and Digest authentication (from HttpAuthProvider). - -## Contents - -There are two examples with exactly the same behavior: -1. DigestExampleMain - shows how to programmatically secure application -2. DigestExampleConfigMain - shows how to secure application with configuration - 1. see src/main/resources/application.yaml for configuration - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-security-webserver-digest-auth.jar -``` - -Try the application: - -The application starts on a random port, the following assumes it is `56551` -```shell -export PORT=38529 -curl http://localhost:${PORT}/public -curl --digest -u "jill:changeit" http://localhost:${PORT}/noRoles -curl --digest -u "john:changeit" http://localhost:${PORT}/user -curl --digest -u "jack:changeit" http://localhost:${PORT}/admin -curl -v --digest -u "john:changeit" http://localhost:${PORT}/deny -curl --digest -u "jack:changeit" http://localhost:${PORT}/noAuthn -``` diff --git a/examples/security/webserver-digest-auth/pom.xml b/examples/security/webserver-digest-auth/pom.xml deleted file mode 100644 index de6656bb48f..00000000000 --- a/examples/security/webserver-digest-auth/pom.xml +++ /dev/null @@ -1,108 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.security - helidon-examples-security-webserver-digest-auth - Helidon Examples Security Digest Authentication - - - This example demonstrates Integration of Web Server based application with Security component and Digest - authentication (from HttpAuthProvider). - - - - io.helidon.examples.security.digest.DigestExampleConfigMain - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver - helidon-webserver-security - - - io.helidon.config - helidon-config-encryption - - - io.helidon.security.providers - helidon-security-providers-http-auth - - - io.helidon.config - helidon-config - - - io.helidon.config - helidon-config-yaml - - - io.helidon.logging - helidon-logging-jul - runtime - - - io.helidon.webclient - helidon-webclient - test - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-core - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/security/webserver-digest-auth/src/main/java/io/helidon/examples/security/digest/DigestExampleBuilderMain.java b/examples/security/webserver-digest-auth/src/main/java/io/helidon/examples/security/digest/DigestExampleBuilderMain.java deleted file mode 100644 index 72a34dbefcf..00000000000 --- a/examples/security/webserver-digest-auth/src/main/java/io/helidon/examples/security/digest/DigestExampleBuilderMain.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (c) 2018, 2024 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.security.digest; - -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import io.helidon.http.HttpMediaTypes; -import io.helidon.logging.common.LogConfig; -import io.helidon.security.Security; -import io.helidon.security.SecurityContext; -import io.helidon.security.providers.httpauth.HttpDigest; -import io.helidon.security.providers.httpauth.HttpDigestAuthProvider; -import io.helidon.security.providers.httpauth.SecureUserStore; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.security.SecurityFeature; - -/** - * Example of HTTP digest authentication with WebServer fully configured programmatically. - */ -@SuppressWarnings("SpellCheckingInspection") -public final class DigestExampleBuilderMain { - // simple approach to user storage - for real world, use data store... - private static final Map USERS = new HashMap<>(); - - private static final char[] HEX_ARRAY = "0123456789abcdef".toCharArray(); - - static { - USERS.put("jack", new MyUser("jack", "changeit".toCharArray(), Set.of("user", "admin"))); - USERS.put("jill", new MyUser("jill", "changeit".toCharArray(), Set.of("user"))); - USERS.put("john", new MyUser("john", "changeit".toCharArray(), Set.of())); - } - - private DigestExampleBuilderMain() { - } - - /** - * Starts this example. Programmatic configuration. See standard output for instructions. - * - * @param args ignored - */ - public static void main(String[] args) { - LogConfig.configureRuntime(); - - WebServerConfig.Builder builder = WebServer.builder(); - setup(builder); - WebServer server = builder.build(); - - long t = System.nanoTime(); - server.start(); - long time = System.nanoTime() - t; - - System.out.printf(""" - Server started in %d ms - - Started server on localhost:%2$d - - Users: - jack/password in roles: user, admin - jill/password in roles: user - john/password in no roles - - *********************** - ** Endpoints: ** - *********************** - - No authentication: http://localhost:%2$d/public - No roles required, authenticated: http://localhost:%2$d/noRoles - User role required: http://localhost:%2$d/user - Admin role required: http://localhost:%2$d/admin - Always forbidden (uses role nobody is in), audited: http://localhost:%2$d/deny - Admin role required, authenticated, authentication optional, audited \ - (always forbidden - challenge is not returned as authentication is optional): http://localhost:%2$d/noAuthn - - """, TimeUnit.MILLISECONDS.convert(time, TimeUnit.NANOSECONDS), server.port()); - } - - static void setup(WebServerConfig.Builder server) { - server.featuresDiscoverServices(false) - .addFeature(SecurityFeature.builder() - .security(security()) - .defaults(SecurityFeature.authenticate()) - .build()) - .routing(routing -> routing - .get("/noRoles", SecurityFeature.enforce()) - .get("/user[/{*}]", SecurityFeature.rolesAllowed("user")) - .get("/admin", SecurityFeature.rolesAllowed("admin")) - // audit is not enabled for GET methods by default - .get("/deny", SecurityFeature.rolesAllowed("deny").audit()) - // roles allowed imply authn and authz - .any("/noAuthn", SecurityFeature.rolesAllowed("admin") - .authenticationOptional() - .audit()) - .get("/{*}", (req, res) -> { - Optional securityContext = req.context().get(SecurityContext.class); - res.headers().contentType(HttpMediaTypes.PLAINTEXT_UTF_8); - res.send("Hello, you are: \n" + securityContext - .map(ctx -> ctx.user().orElse(SecurityContext.ANONYMOUS).toString()) - .orElse("Security context is null")); - })); - } - - private static Security security() { - return Security.builder() - .addAuthenticationProvider( - HttpDigestAuthProvider.builder() - .realm("mic") - .digestServerSecret("changeit".toCharArray()) - .userStore(buildUserStore()), - "digest-auth") - .build(); - } - - private static SecureUserStore buildUserStore() { - return login -> Optional.ofNullable(USERS.get(login)); - } - - private record MyUser(String login, char[] password, Set roles) implements SecureUserStore.User { - - private static String bytesToHex(byte[] bytes) { - char[] hexChars = new char[bytes.length * 2]; - for (int j = 0; j < bytes.length; j++) { - int v = bytes[j] & 0xFF; - hexChars[j * 2] = HEX_ARRAY[v >>> 4]; - hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; - } - return new String(hexChars); - } - - @Override - public boolean isPasswordValid(char[] password) { - return Arrays.equals(password(), password); - } - - @Override - public Optional digestHa1(String realm, HttpDigest.Algorithm algorithm) { - if (algorithm != HttpDigest.Algorithm.MD5) { - throw new IllegalArgumentException("Unsupported algorithm " + algorithm); - } - String a1 = login + ":" + realm + ":" + new String(password()); - byte[] bytes = a1.getBytes(StandardCharsets.UTF_8); - MessageDigest digest; - try { - digest = MessageDigest.getInstance("MD5"); - } catch (NoSuchAlgorithmException e) { - throw new IllegalStateException("MD5 algorithm should be supported", e); - } - return Optional.of(bytesToHex(digest.digest(bytes))); - } - } -} diff --git a/examples/security/webserver-digest-auth/src/main/java/io/helidon/examples/security/digest/DigestExampleConfigMain.java b/examples/security/webserver-digest-auth/src/main/java/io/helidon/examples/security/digest/DigestExampleConfigMain.java deleted file mode 100644 index 727f68e7840..00000000000 --- a/examples/security/webserver-digest-auth/src/main/java/io/helidon/examples/security/digest/DigestExampleConfigMain.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.security.digest; - -import java.util.Optional; -import java.util.concurrent.TimeUnit; - -import io.helidon.config.Config; -import io.helidon.http.HttpMediaTypes; -import io.helidon.logging.common.LogConfig; -import io.helidon.security.SecurityContext; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; - -/** - * Example of HTTP digest authentication with Web Server fully configured in config file. - */ -public final class DigestExampleConfigMain { - private DigestExampleConfigMain() { - } - - /** - * Starts this example. Loads configuration from src/main/resources/application.conf. See standard output for instructions. - * - * @param args ignored - */ - public static void main(String[] args) { - LogConfig.configureRuntime(); - - WebServerConfig.Builder builder = WebServer.builder(); - setup(builder); - WebServer server = builder.build(); - - long t = System.nanoTime(); - server.start(); - long time = System.nanoTime() - t; - - System.out.printf(""" - Server started in %d ms - - Started server on localhost:%2$d - - Users: - jack/password in roles: user, admin - jill/password in roles: user - john/password in no roles - - *********************** - ** Endpoints: ** - *********************** - - No authentication: http://localhost:%2$d/public - No roles required, authenticated: http://localhost:%2$d/noRoles - User role required: http://localhost:%2$d/user - Admin role required: http://localhost:%2$d/admin - Always forbidden (uses role nobody is in), audited: http://localhost:%2$d/deny - Admin role required, authenticated, authentication optional, audited \ - (always forbidden - challenge is not returned as authentication is optional): http://localhost:%2$d/noAuthn - - """, TimeUnit.MILLISECONDS.convert(time, TimeUnit.NANOSECONDS), server.port()); - } - - static void setup(WebServerConfig.Builder server) { - Config config = Config.create(); - server.config(config.get("server")) - .routing(routing -> routing - // web server does not (yet) have possibility to configure routes in config files, so explicit... - .get("/{*}", (req, res) -> { - Optional securityContext = req.context().get(SecurityContext.class); - res.headers().contentType(HttpMediaTypes.PLAINTEXT_UTF_8); - res.send("Hello, you are: \n" + securityContext - .map(ctx -> ctx.user().orElse(SecurityContext.ANONYMOUS).toString()) - .orElse("Security context is null")); - })); - } -} diff --git a/examples/security/webserver-digest-auth/src/main/java/io/helidon/examples/security/digest/package-info.java b/examples/security/webserver-digest-auth/src/main/java/io/helidon/examples/security/digest/package-info.java deleted file mode 100644 index 7403fd34d8a..00000000000 --- a/examples/security/webserver-digest-auth/src/main/java/io/helidon/examples/security/digest/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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 of Digest authentication on top of RX web server. - * - * @see io.helidon.examples.security.digest.DigestExampleConfigMain Configuration based example - * @see io.helidon.examples.security.digest.DigestExampleBuilderMain Programmatic example - */ -package io.helidon.examples.security.digest; diff --git a/examples/security/webserver-digest-auth/src/main/resources/application.yaml b/examples/security/webserver-digest-auth/src/main/resources/application.yaml deleted file mode 100644 index cc933bea773..00000000000 --- a/examples/security/webserver-digest-auth/src/main/resources/application.yaml +++ /dev/null @@ -1,60 +0,0 @@ -# -# Copyright (c) 2016, 2024 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: - features: - security: - # Configuration of integration with web server - defaults: - authenticate: true - paths: - - path: "/noRoles" - methods: [ "get" ] - - path: "/user[/{*}]" - methods: [ "get" ] - roles-allowed: [ "user" ] - - path: "/admin" - methods: [ "get" ] - roles-allowed: [ "admin" ] - - path: "/deny" - methods: [ "get" ] - roles-allowed: [ "deny" ] - audit: true - - path: "/noAuthn" - roles-allowed: [ "admin" ] - authentication-optional: true - audit: true - - -security: - config: - # Configuration of secured config (encryption of passwords in property files) - # Set to true for production - if set to true, clear text passwords will cause failure - require-encryption: false - providers: - - http-digest-auth: - realm: "mic" - server-secret: "changeit" - users: - - login: "jack" - password: "${CLEAR=changeit}" - roles: ["user", "admin"] - - login: "jill" - password: "${CLEAR=changeit}" - roles: ["user"] - - login: "john" - password: "${CLEAR=changeit}" - roles: [] diff --git a/examples/security/webserver-digest-auth/src/main/resources/logging.properties b/examples/security/webserver-digest-auth/src/main/resources/logging.properties deleted file mode 100644 index 5d2c493107b..00000000000 --- a/examples/security/webserver-digest-auth/src/main/resources/logging.properties +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) 2018, 2023 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. -# - -handlers=io.helidon.logging.jul.HelidonConsoleHandler -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 -#All log level details -.level=WARNING -io.helidon.security.level=FINEST -AUDIT.level=FINEST diff --git a/examples/security/webserver-digest-auth/src/test/java/io/helidon/examples/security/digest/DigestAuthenticator.java b/examples/security/webserver-digest-auth/src/test/java/io/helidon/examples/security/digest/DigestAuthenticator.java deleted file mode 100644 index 04bf5c9186e..00000000000 --- a/examples/security/webserver-digest-auth/src/test/java/io/helidon/examples/security/digest/DigestAuthenticator.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (c) 2023 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.security.digest; - -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.util.Locale; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Poorly inspired from {@code org.glassfish.jersey.client.authentication.DigestAuthenticator}. - */ -class DigestAuthenticator { - - private static final char[] HEX_ARRAY = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - private static final Pattern KEY_VALUE_PAIR_PATTERN = Pattern.compile("(\\w+)\\s*=\\s*(\"([^\"]+)\"|(\\w+))\\s*,?\\s*"); - - private final SecureRandom random = new SecureRandom(); - - /** - * Respond to the challenge. - * - * @param challenge response challenge - * @param uri request uri - * @param method request method - * @param username username - * @param password password - * @return authorization header value or {@code null} - */ - String authorization(String challenge, String uri, String method, String username, String password) { - DigestScheme ds = parseDigestScheme(challenge); - return ds != null ? header(ds, uri, method, username, password) : null; - } - - private String header(DigestScheme ds, String uri, String method, String username, String password) { - StringBuilder sb = new StringBuilder(100); - sb.append("Digest "); - append(sb, "username", username); - append(sb, "realm", ds.realm()); - append(sb, "nonce", ds.nonce()); - append(sb, "opaque", ds.opaque()); - append(sb, "algorithm", ds.algorithm(), false); - append(sb, "qop", ds.qop(), false); - append(sb, "uri", uri); - - String ha1; - if (ds.algorithm().equals("MD5_SESS")) { - ha1 = md5(md5(username, ds.realm(), password)); - } else { - ha1 = md5(username, ds.realm(), password); - } - - String ha2 = md5(method, uri); - String response; - if (ds.qop() == null) { - response = md5(ha1, ds.nonce(), ha2); - } else { - String cnonce = randomBytes(); // client nonce - append(sb, "cnonce", cnonce); - String nc = String.format("%08x", ds.nc.incrementAndGet()); // counter - append(sb, "nc", nc, false); - response = md5(ha1, ds.nonce(), nc, cnonce, ds.qop(), ha2); - } - append(sb, "response", response); - return sb.toString(); - } - - private static void append(StringBuilder sb, String key, String value, boolean useQuote) { - if (value == null) { - return; - } - if (sb.length() > 0) { - if (sb.charAt(sb.length() - 1) != ' ') { - sb.append(','); - } - } - sb.append(key); - sb.append('='); - if (useQuote) { - sb.append('"'); - } - sb.append(value); - if (useQuote) { - sb.append('"'); - } - } - - private static void append(StringBuilder sb, String key, String value) { - append(sb, key, value, true); - } - - private static String bytesToHex(byte[] bytes) { - char[] hexChars = new char[bytes.length * 2]; - int v; - for (int j = 0; j < bytes.length; j++) { - v = bytes[j] & 0xFF; - hexChars[j * 2] = HEX_ARRAY[v >>> 4]; - hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; - } - return new String(hexChars); - } - - private static String md5(String... tokens) { - StringBuilder sb = new StringBuilder(100); - for (String token : tokens) { - if (sb.length() > 0) { - sb.append(':'); - } - sb.append(token); - } - - MessageDigest md; - try { - md = MessageDigest.getInstance("MD5"); - } catch (NoSuchAlgorithmException ex) { - throw new RuntimeException(ex.getMessage()); - } - md.update(sb.toString().getBytes(StandardCharsets.UTF_8), 0, sb.length()); - byte[] md5hash = md.digest(); - return bytesToHex(md5hash); - } - - - private String randomBytes() { - byte[] bytes = new byte[4]; - random.nextBytes(bytes); - return bytesToHex(bytes); - } - - private record DigestScheme(String realm, - String nonce, - String opaque, - String qop, - String algorithm, - boolean stale, - AtomicInteger nc) { - } - - static DigestScheme parseDigestScheme(String header) { - String[] parts = header.trim().split("\\s+", 2); - if (parts.length != 2) { - return null; - } - if (!"digest".equals(parts[0].toLowerCase(Locale.ROOT))) { - return null; - } - String realm = null; - String nonce = null; - String opaque = null; - String qop = null; - String algorithm = null; - boolean stale = false; - Matcher match = KEY_VALUE_PAIR_PATTERN.matcher(parts[1]); - while (match.find()) { - // expect 4 groups (key)=("(val)" | (val)) - int nbGroups = match.groupCount(); - if (nbGroups != 4) { - continue; - } - String key = match.group(1); - String valNoQuotes = match.group(3); - String valQuotes = match.group(4); - String val = (valNoQuotes == null) ? valQuotes : valNoQuotes; - if ("qop".equals(key)) { - qop = val.contains("auth") ? "auth" : null; - } else if ("realm".equals(key)) { - realm = val; - } else if ("nonce".equals(key)) { - nonce = val; - } else if ("opaque".equals(key)) { - opaque = val; - } else if ("stale".equals(key)) { - stale = Boolean.parseBoolean(val); - } else if ("algorithm".equals(key)) { - if (val == null || val.isBlank()) { - continue; - } - val = val.trim(); - if (val.contains("MD5-sess") || val.contains("MD5-sess".toLowerCase(Locale.ROOT))) { - algorithm = "MD5-sess"; - } else { - algorithm = "MD5"; - } - } - } - return new DigestScheme(realm, nonce, opaque, qop, algorithm, stale, new AtomicInteger(0)); - } -} diff --git a/examples/security/webserver-digest-auth/src/test/java/io/helidon/examples/security/digest/DigestExampleBuilderTest.java b/examples/security/webserver-digest-auth/src/test/java/io/helidon/examples/security/digest/DigestExampleBuilderTest.java deleted file mode 100644 index 7f49c17ca44..00000000000 --- a/examples/security/webserver-digest-auth/src/test/java/io/helidon/examples/security/digest/DigestExampleBuilderTest.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.security.digest; - -import java.net.URI; - -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webserver.WebServerConfig; - -/** - * Unit test for {@link DigestExampleBuilderMain}. - */ -@ServerTest -public class DigestExampleBuilderTest extends DigestExampleTest { - - DigestExampleBuilderTest(Http1Client client, URI uri) { - super(client, uri); - } - - @SetUpServer - public static void setup(WebServerConfig.Builder server) { - DigestExampleBuilderMain.setup(server); - } -} diff --git a/examples/security/webserver-digest-auth/src/test/java/io/helidon/examples/security/digest/DigestExampleConfigTest.java b/examples/security/webserver-digest-auth/src/test/java/io/helidon/examples/security/digest/DigestExampleConfigTest.java deleted file mode 100644 index 64957fd856b..00000000000 --- a/examples/security/webserver-digest-auth/src/test/java/io/helidon/examples/security/digest/DigestExampleConfigTest.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.security.digest; - -import java.net.URI; - -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webserver.WebServerConfig; - -/** - * Unit test for {@link DigestExampleConfigMain}. - */ -@ServerTest -public class DigestExampleConfigTest extends DigestExampleTest { - - DigestExampleConfigTest(Http1Client client, URI uri) { - super(client, uri); - } - - @SetUpServer - public static void setup(WebServerConfig.Builder server) { - DigestExampleConfigMain.setup(server); - } -} diff --git a/examples/security/webserver-digest-auth/src/test/java/io/helidon/examples/security/digest/DigestExampleTest.java b/examples/security/webserver-digest-auth/src/test/java/io/helidon/examples/security/digest/DigestExampleTest.java deleted file mode 100644 index 4c1aeb3fc69..00000000000 --- a/examples/security/webserver-digest-auth/src/test/java/io/helidon/examples/security/digest/DigestExampleTest.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2018, 2024 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.security.digest; - -import java.net.URI; -import java.util.Set; - -import io.helidon.http.HeaderNames; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; - -import org.junit.jupiter.api.Test; - -import static io.helidon.examples.security.digest.WebClientAuthenticationService.HTTP_AUTHENTICATION_PASSWORD; -import static io.helidon.examples.security.digest.WebClientAuthenticationService.HTTP_AUTHENTICATION_USERNAME; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Abstract class with tests for this example (used by programmatic and config based tests). - */ -public abstract class DigestExampleTest { - - private final Http1Client client; - private final Http1Client authClient; - - DigestExampleTest(Http1Client client, URI uri) { - this.client = client; - this.authClient = Http1Client.builder() - .baseUri(uri) - .addService(new WebClientAuthenticationService()) - .build(); - } - - //now for the tests - @Test - public void testPublic() { - //Must be accessible without authentication - try (Http1ClientResponse response = client.get().path("/public").request()) { - assertThat(response.status().code(), is(200)); - String entity = response.entity().as(String.class); - assertThat(entity, containsString("")); - } - } - - @Test - public void testNoRoles() { - String uri = "/noRoles"; - - testNotAuthorized(uri); - - //Must be accessible with authentication - to everybody - testProtected(uri, "jack", "changeit", Set.of("admin", "user"), Set.of()); - testProtected(uri, "jill", "changeit", Set.of("user"), Set.of("admin")); - testProtected(uri, "john", "changeit", Set.of(), Set.of("admin", "user")); - } - - @Test - public void testUserRole() { - String uri = "/user"; - - testNotAuthorized(uri); - - //Jack and Jill allowed (user role) - testProtected(uri, "jack", "changeit", Set.of("admin", "user"), Set.of()); - testProtected(uri, "jill", "changeit", Set.of("user"), Set.of("admin")); - testProtectedDenied(uri, "john", "changeit"); - } - - @Test - public void testAdminRole() { - String uri = "/admin"; - - testNotAuthorized(uri); - - //Only jack is allowed - admin role... - testProtected(uri, "jack", "changeit", Set.of("admin", "user"), Set.of()); - testProtectedDenied(uri, "jill", "changeit"); - testProtectedDenied(uri, "john", "changeit"); - } - - @Test - public void testDenyRole() { - String uri = "/deny"; - - testNotAuthorized(uri); - - // nobody has the correct role - testProtectedDenied(uri, "jack", "changeit"); - testProtectedDenied(uri, "jill", "changeit"); - testProtectedDenied(uri, "john", "changeit"); - } - - @Test - public void getNoAuthn() { - String uri = "/noAuthn"; - //Must NOT be accessible without authentication - try (Http1ClientResponse response = client.get(uri).request()) { - // authentication is optional, so we are not challenged, only forbidden, as the role can never be there... - assertThat(response.status().code(), is(403)); - - // doesn't matter, we are never challenged - testProtectedDenied(uri, "jack", "changeit"); - testProtectedDenied(uri, "jill", "changeit"); - testProtectedDenied(uri, "john", "changeit"); - } - } - - private void testNotAuthorized(String uri) { - //Must NOT be accessible without authentication - try (Http1ClientResponse response = client.get().path(uri).request()) { - assertThat(response.status().code(), is(401)); - String header = response.headers().first(HeaderNames.create("WWW-Authenticate")).orElse(null); - assertThat(header, notNullValue()); - assertThat(header.toLowerCase(), containsString("digest")); - assertThat(header, containsString("mic")); - } - } - - private Http1ClientResponse callProtected(String uri, String username, String password) { - // here we call the endpoint - return authClient - .get(uri) - .property(HTTP_AUTHENTICATION_USERNAME, username) - .property(HTTP_AUTHENTICATION_PASSWORD, password) - .request(); - } - - private void testProtectedDenied(String uri, String username, String password) { - try (Http1ClientResponse response = callProtected(uri, username, password)) { - assertThat(response.status().code(), is(403)); - } - } - - private void testProtected(String uri, - String username, - String password, - Set expectedRoles, - Set invalidRoles) { - - try (Http1ClientResponse response = callProtected(uri, username, password)) { - - assertThat(response.status().code(), is(200)); - - String entity = response.entity().as(String.class); - - // check login - assertThat(entity, containsString("id='" + username + "'")); - // check roles - expectedRoles.forEach(role -> assertThat(entity, containsString(":" + role))); - invalidRoles.forEach(role -> assertThat(entity, not(containsString(":" + role)))); - } - } - -} diff --git a/examples/security/webserver-digest-auth/src/test/java/io/helidon/examples/security/digest/WebClientAuthenticationService.java b/examples/security/webserver-digest-auth/src/test/java/io/helidon/examples/security/digest/WebClientAuthenticationService.java deleted file mode 100644 index 76c32d4cb68..00000000000 --- a/examples/security/webserver-digest-auth/src/test/java/io/helidon/examples/security/digest/WebClientAuthenticationService.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2023 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.security.digest; - -import java.util.Map; - -import io.helidon.http.HeaderNames; -import io.helidon.http.Status; -import io.helidon.webclient.api.WebClientServiceRequest; -import io.helidon.webclient.api.WebClientServiceResponse; -import io.helidon.webclient.spi.WebClientService; - -/** - * Web client service that supports digest authentication. - * Temporary until https://github.com/helidon-io/helidon/issues/7207 is fixed. - */ -class WebClientAuthenticationService implements WebClientService { - - /** - * Property name for username. - */ - static final String HTTP_AUTHENTICATION_USERNAME = "helidon.config.client.http.auth.username"; - - /** - * Property name for password. - */ - static final String HTTP_AUTHENTICATION_PASSWORD = "helidon.config.client.http.auth.password"; - - private final DigestAuthenticator digestAuth = new DigestAuthenticator(); - - @Override - public WebClientServiceResponse handle(Chain chain, WebClientServiceRequest request) { - WebClientServiceResponse response = chain.proceed(request); - if (response.status() != Status.UNAUTHORIZED_401) { - return response; - } - Map properties = request.properties(); - String username = properties.get(HTTP_AUTHENTICATION_USERNAME); - String password = properties.get(HTTP_AUTHENTICATION_PASSWORD); - if (username == null || password == null) { - return response; - } - String challenge = response.headers().first(HeaderNames.WWW_AUTHENTICATE).orElse(null); - if (challenge == null) { - return response; - } - String uri = request.uri().path().path(); - String method = request.method().text(); - String atz = digestAuth.authorization(challenge, uri, method, username, password); - if (atz == null) { - return response; - } - request.headers().add(HeaderNames.AUTHORIZATION, atz); - return chain.proceed(request); - } -} diff --git a/examples/security/webserver-signatures/README.md b/examples/security/webserver-signatures/README.md deleted file mode 100644 index 3fbd0d5dbb1..00000000000 --- a/examples/security/webserver-signatures/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# Web Server Integration and HTTP Signatures - -This example demonstrates Integration of WebServer -based application with Security component and HTTP Signatures. - -## Contents - -There are two examples with exactly the same behavior -1. builder - shows how to programmatically secure application -2. config - shows how to secure application with configuration - 1. see `src/main/resources/service1.yaml` and `src/main/resources/service2.conf` for configuration -3. Each consists of two services - 1. "public" service protected by basic authentication (for simplicity) - 2. "internal" service protected by a combination of basic authentication (for user propagation) and http signature - (for service authentication) - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-security-webserver-signatures.jar -``` - -Try the endpoints (port is random, shall be replaced accordingly): -```shell -export PORT=34941 -curl -u "jack:changeit" http://localhost:${PORT}/service1 -curl -u "jill:changeit" http://localhost:${PORT}/service1-rsa -curl -v -u "john:changeit" http://localhost:${PORT}/service1 -``` diff --git a/examples/security/webserver-signatures/pom.xml b/examples/security/webserver-signatures/pom.xml deleted file mode 100644 index d8adea65c95..00000000000 --- a/examples/security/webserver-signatures/pom.xml +++ /dev/null @@ -1,102 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.security - helidon-examples-security-webserver-signatures - Helidon Examples Security HTTP Signatures - - - This example demonstrates Integration of Web Server based application with Security component and HTTP - Signatures - - - - io.helidon.examples.security.signatures.SignatureExampleConfigMain - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver - helidon-webserver-security - - - io.helidon.security.providers - helidon-security-providers-http-sign - - - io.helidon.webclient - helidon-webclient-security - - - io.helidon.bundles - helidon-bundles-security - - - io.helidon.bundles - helidon-bundles-config - - - io.helidon.config - helidon-config-hocon - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/security/webserver-signatures/src/main/java/io/helidon/examples/security/signatures/Service1.java b/examples/security/webserver-signatures/src/main/java/io/helidon/examples/security/signatures/Service1.java deleted file mode 100644 index ccb6bc8f11e..00000000000 --- a/examples/security/webserver-signatures/src/main/java/io/helidon/examples/security/signatures/Service1.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2023 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.security.signatures; - -import io.helidon.common.LazyValue; -import io.helidon.common.context.Contexts; -import io.helidon.http.HttpMediaTypes; -import io.helidon.http.Status; -import io.helidon.security.SecurityContext; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -class Service1 implements HttpService { - - private final LazyValue client = LazyValue.create(() -> Contexts.context() - .flatMap(c -> c.get(WebServer.class)) - .map(server -> Http1Client.builder() - .baseUri("http://localhost:" + server.port("service2")) - .build()) - .orElseThrow(() -> new IllegalStateException("Unable to get server instance from current context"))); - - @Override - public void routing(HttpRules rules) { - rules.get("/service1", this::service1) - .get("/service1-rsa", this::service1Rsa); - } - - private void service1(ServerRequest req, ServerResponse res) { - handle(req, res, "/service2"); - } - - private void service1Rsa(ServerRequest req, ServerResponse res) { - handle(req, res, "/service2-rsa"); - } - - private void handle(ServerRequest req, ServerResponse res, String path) { - res.headers().contentType(HttpMediaTypes.PLAINTEXT_UTF_8); - req.context() - .get(SecurityContext.class) - .ifPresentOrElse(context -> { - try (Http1ClientResponse clientRes = client.get().get(path).request()) { - if (clientRes.status() == Status.OK_200) { - res.send(clientRes.entity().as(String.class)); - } else { - res.send("Request failed, status: " + clientRes.status()); - } - } - }, () -> res.send("Security context is null")); - } -} diff --git a/examples/security/webserver-signatures/src/main/java/io/helidon/examples/security/signatures/Service2.java b/examples/security/webserver-signatures/src/main/java/io/helidon/examples/security/signatures/Service2.java deleted file mode 100644 index 82f1092c187..00000000000 --- a/examples/security/webserver-signatures/src/main/java/io/helidon/examples/security/signatures/Service2.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2023 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.security.signatures; - -import java.util.Optional; - -import io.helidon.http.HttpMediaTypes; -import io.helidon.security.SecurityContext; -import io.helidon.security.Subject; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -class Service2 implements HttpService { - - @Override - public void routing(HttpRules rules) { - rules.get("/{*}", this::handle); - } - - private void handle(ServerRequest req, ServerResponse res) { - Optional securityContext = req.context().get(SecurityContext.class); - res.headers().contentType(HttpMediaTypes.PLAINTEXT_UTF_8); - res.send("Response from service2, you are: \n" + securityContext - .flatMap(SecurityContext::user) - .map(Subject::toString) - .orElse("Security context is null") + ", service: " + securityContext - .flatMap(SecurityContext::service) - .map(Subject::toString)); - } -} diff --git a/examples/security/webserver-signatures/src/main/java/io/helidon/examples/security/signatures/SignatureExampleBuilderMain.java b/examples/security/webserver-signatures/src/main/java/io/helidon/examples/security/signatures/SignatureExampleBuilderMain.java deleted file mode 100644 index 6a65aac5beb..00000000000 --- a/examples/security/webserver-signatures/src/main/java/io/helidon/examples/security/signatures/SignatureExampleBuilderMain.java +++ /dev/null @@ -1,242 +0,0 @@ - -/* - * Copyright (c) 2018, 2024 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.security.signatures; - -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.TimeUnit; - -import io.helidon.common.configurable.Resource; -import io.helidon.common.pki.Keys; -import io.helidon.security.CompositeProviderFlag; -import io.helidon.security.CompositeProviderSelectionPolicy; -import io.helidon.security.Security; -import io.helidon.security.providers.common.OutboundConfig; -import io.helidon.security.providers.common.OutboundTarget; -import io.helidon.security.providers.httpauth.HttpBasicAuthProvider; -import io.helidon.security.providers.httpauth.SecureUserStore; -import io.helidon.security.providers.httpsign.HttpSignProvider; -import io.helidon.security.providers.httpsign.InboundClientDefinition; -import io.helidon.security.providers.httpsign.OutboundTargetDefinition; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.context.ContextFeature; -import io.helidon.webserver.http.HttpRouting; -import io.helidon.webserver.security.SecurityFeature; -import io.helidon.webserver.security.SecurityHttpFeature; - -/** - * Example of authentication of service with http signatures, using configuration file as much as possible. - */ -@SuppressWarnings("DuplicatedCode") -public class SignatureExampleBuilderMain { - - private static final Map USERS = new HashMap<>(); - - static { - addUser("jack", "changeit", List.of("user", "admin")); - addUser("jill", "changeit", List.of("user")); - addUser("john", "changeit", List.of()); - } - - private SignatureExampleBuilderMain() { - } - - private static void addUser(String user, String password, List roles) { - USERS.put(user, new SecureUserStore.User() { - @Override - public String login() { - return user; - } - - char[] password() { - return password.toCharArray(); - } - - @Override - public boolean isPasswordValid(char[] password) { - return Arrays.equals(password(), password); - } - - @Override - public Collection roles() { - return roles; - } - }); - } - - /** - * Starts this example. - * - * @param args ignored - */ - public static void main(String[] args) { - WebServerConfig.Builder builder = WebServer.builder(); - setup(builder); - WebServer server = builder.build(); - server.context().register(server); - - long t = System.nanoTime(); - server.start(); - long time = System.nanoTime() - t; - - System.out.printf(""" - Server started in %1d ms - - Signature example: from builder - - Users: - jack/password in roles: user, admin - jill/password in roles: user - john/password in no roles - - *********************** - ** Endpoints: ** - *********************** - - Basic authentication, user role required, will use symmetric signatures for outbound: - http://localhost:%2$d/service1 - Basic authentication, user role required, will use asymmetric signatures for outbound: - http://localhost:%3$d/service1-rsa - - """, TimeUnit.MILLISECONDS.convert(time, TimeUnit.NANOSECONDS), server.port(), server.port("service2")); - } - - static void setup(WebServerConfig.Builder server) { - // as we explicitly configure SecurityHttpFeature, we must disable automated loading of security, - // as it would add another feature with different configuration - server.featuresDiscoverServices(false) - // context is a required pre-requisite of security - .addFeature(ContextFeature.create()) - .routing(SignatureExampleBuilderMain::routing1) - .putSocket("service2", socket -> socket - .routing(SignatureExampleBuilderMain::routing2)); - } - - private static void routing2(HttpRouting.Builder routing) { - SecurityHttpFeature security = SecurityHttpFeature.create(security2()) - .securityDefaults(SecurityFeature.authenticate()); - - routing.addFeature(security) - .get("/service2*", SecurityFeature.rolesAllowed("user")) - .register(new Service2()); - } - - private static void routing1(HttpRouting.Builder routing) { - SecurityHttpFeature security = SecurityHttpFeature.create(security1()) - .securityDefaults(SecurityFeature.authenticate()); - routing.addFeature(security) - .get("/service1*", SecurityFeature.rolesAllowed("user")) - .register(new Service1()); - } - - private static Security security2() { - return Security.builder() - .providerSelectionPolicy(CompositeProviderSelectionPolicy - .builder() - .addAuthenticationProvider("http-signatures", CompositeProviderFlag.OPTIONAL) - .addAuthenticationProvider("basic-auth") - .build()) - .addProvider(HttpBasicAuthProvider - .builder() - .realm("mic") - .userStore(users()), - "basic-auth") - .addProvider(HttpSignProvider.builder() - .addInbound(InboundClientDefinition - .builder("service1-hmac") - .principalName("Service1 - HMAC signature") - .hmacSecret("changeit") - .build()) - .addInbound(InboundClientDefinition - .builder("service1-rsa") - .principalName("Service1 - RSA signature") - .publicKeyConfig(Keys.builder() - .keystore(k -> k - .keystore(Resource.create("keystore.p12")) - .passphrase("changeit") - .certAlias("service_cert") - .build()) - .build()) - .build()), - "http-signatures") - .build(); - } - - private static Security security1() { - return Security.builder() - .providerSelectionPolicy(CompositeProviderSelectionPolicy - .builder() - .addOutboundProvider("basic-auth") - .addOutboundProvider("http-signatures") - .build()) - .addProvider(HttpBasicAuthProvider - .builder() - .realm("mic") - .userStore(users()) - .addOutboundTarget(OutboundTarget.builder("propagate-all").build()), - "basic-auth") - .addProvider(HttpSignProvider - .builder() - .outbound(OutboundConfig - .builder() - .addTarget(hmacTarget()) - .addTarget(rsaTarget()) - .build()), - "http-signatures") - .build(); - } - - private static OutboundTarget rsaTarget() { - return OutboundTarget.builder("service2-rsa") - .addHost("localhost") - .addPath("/service2-rsa.*") - .customObject(OutboundTargetDefinition.class, - OutboundTargetDefinition.builder("service1-rsa") - .privateKeyConfig(Keys.builder() - .keystore(k -> k - .keystore(Resource.create("keystore.p12")) - .passphrase("changeit") - .keyAlias("myPrivateKey") - .build()) - .build()) - .build()) - .build(); - } - - private static OutboundTarget hmacTarget() { - return OutboundTarget.builder("service2") - .addHost("localhost") - .addPath("/service2") - .customObject( - OutboundTargetDefinition.class, - OutboundTargetDefinition - .builder("service1-hmac") - .hmacSecret("changeit") - .build()) - .build(); - } - - private static SecureUserStore users() { - return login -> Optional.ofNullable(USERS.get(login)); - } -} diff --git a/examples/security/webserver-signatures/src/main/java/io/helidon/examples/security/signatures/SignatureExampleConfigMain.java b/examples/security/webserver-signatures/src/main/java/io/helidon/examples/security/signatures/SignatureExampleConfigMain.java deleted file mode 100644 index 993c698f609..00000000000 --- a/examples/security/webserver-signatures/src/main/java/io/helidon/examples/security/signatures/SignatureExampleConfigMain.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2018, 2024 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.security.signatures; - -import java.util.concurrent.TimeUnit; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.context.ContextFeature; -import io.helidon.webserver.http.HttpRouting; -import io.helidon.webserver.security.SecurityHttpFeature; - -/** - * Example of authentication of service with http signatures, using configuration file as much as possible. - */ -@SuppressWarnings("DuplicatedCode") -public class SignatureExampleConfigMain { - - private SignatureExampleConfigMain() { - } - - /** - * Starts this example. - * - * @param args ignored - */ - public static void main(String[] args) { - WebServerConfig.Builder builder = WebServer.builder(); - setup(builder); - WebServer server = builder.build(); - server.context().register(server); - - long t = System.nanoTime(); - server.start(); - long time = System.nanoTime() - t; - - System.out.printf(""" - Server started in %1d ms - - Signature example: from config - - Users: - jack/password in roles: user, admin - jill/password in roles: user - john/password in no roles - - *********************** - ** Endpoints: ** - *********************** - - Basic authentication, user role required, will use symmetric signatures for outbound: - http://localhost:%2$d/service1 - Basic authentication, user role required, will use asymmetric signatures for outbound: - http://localhost:%3$d/service1-rsa - - """, TimeUnit.MILLISECONDS.convert(time, TimeUnit.NANOSECONDS), server.port(), server.port("service2")); - } - - static void setup(WebServerConfig.Builder server) { - // as we explicitly configure SecurityHttpFeature, we must disable automated loading of security, - // as it would add another feature with different configuration - server.featuresDiscoverServices(false) - // context is a required pre-requisite of security - .addFeature(ContextFeature.create()) - .routing(SignatureExampleConfigMain::routing1) - .putSocket("service2", socket -> socket - .routing(SignatureExampleConfigMain::routing2)); - } - - private static void routing2(HttpRouting.Builder routing) { - // build routing (security is loaded from config) - Config config = config("service2.yaml"); - - // helper method to load both security and web server security from configuration - routing.addFeature(SecurityHttpFeature.create(config.get("security.web-server"))) - .register(new Service2()); - } - - private static void routing1(HttpRouting.Builder routing) { - // build routing (security is loaded from config) - Config config = config("service1.yaml"); - - // helper method to load both security and web server security from configuration - routing.addFeature(SecurityHttpFeature.create(config.get("security.web-server"))) - .register(new Service1()); - } - - private static Config config(String confFile) { - return Config.builder() - .sources(ConfigSources.classpath(confFile)) - .build(); - } -} diff --git a/examples/security/webserver-signatures/src/main/java/io/helidon/examples/security/signatures/package-info.java b/examples/security/webserver-signatures/src/main/java/io/helidon/examples/security/signatures/package-info.java deleted file mode 100644 index 16061e6356e..00000000000 --- a/examples/security/webserver-signatures/src/main/java/io/helidon/examples/security/signatures/package-info.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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 of HTTP Signatures (both inbound and outbound). - * Based on RFC draft: https://tools.ietf - * .org/html/draft-cavage-http-signatures-03 - */ -package io.helidon.examples.security.signatures; diff --git a/examples/security/webserver-signatures/src/main/resources/keystore.p12 b/examples/security/webserver-signatures/src/main/resources/keystore.p12 deleted file mode 100644 index 96df596265a4799186924602afa1d101e5e80baa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2693 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 diff --git a/examples/security/webserver-signatures/src/main/resources/service1.yaml b/examples/security/webserver-signatures/src/main/resources/service1.yaml deleted file mode 100644 index 7af4407c1cf..00000000000 --- a/examples/security/webserver-signatures/src/main/resources/service1.yaml +++ /dev/null @@ -1,83 +0,0 @@ -# -# Copyright (c) 2016, 2024 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. -# - -security: - config: - # Configuration of secured config (encryption of passwords in property files) - # Set to true for production - if set to true, clear text passwords will cause failure - require-encryption: false - - # composite provider policy - provider-policy: - type: "COMPOSITE" - outbound: - - name: "http-basic-auth" - - name: "http-signatures" - - providers: - # Security provider - basic authentication (supports roles) - default - - http-basic-auth: - realm: "helidon" - users: - - login: "jack" - password: "${CLEAR=changeit}" - roles: ["user", "admin"] - - login: "jill" - # master password is "changeit", password is "changeit" - password: "${CLEAR=changeit}" - roles: ["user"] - - login: "john" - password: "${CLEAR=changeit}" - roles: [] - outbound: - - name: "propagate-all" - # only configured for outbound security - - http-signatures: - outbound: - - name: "service2" - hosts: ["localhost"] - paths: ["/service2"] - signature: - key-id: "service1-hmac" - hmac.secret: "${CLEAR=changeit}" - - name: "service2-rsa" - hosts: ["localhost"] - paths: ["/service2-rsa.*"] - signature: - key-id: "service1-rsa" - private-key: - keystore: - # path to keystore - resource.path: "src/main/resources/keystore.p12" - # Keystore type - # PKCS12, JSK or RSA (not really a keystore, but directly the linux style private key unencrypted) - # defaults to jdk default - type: "PKCS12" - # password of the keystore - passphrase: "changeit" - # alias of the key to sign request - key.alias: "myPrivateKey" - web-server: - # Configuration of integration with web server - defaults: - authenticate: true - paths: - - path: "/service1" - methods: ["get"] - roles-allowed: ["user"] - - path: "/service1-rsa" - methods: ["get"] - roles-allowed: ["user"] diff --git a/examples/security/webserver-signatures/src/main/resources/service2.yaml b/examples/security/webserver-signatures/src/main/resources/service2.yaml deleted file mode 100644 index 55f426a506f..00000000000 --- a/examples/security/webserver-signatures/src/main/resources/service2.yaml +++ /dev/null @@ -1,75 +0,0 @@ -# -# Copyright (c) 2016, 2024 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. -# - -security: - config: - # Configuration of secured config (encryption of passwords in property files) - # Set to true for production - if set to true, clear text passwords will cause failure - require-encryption: false - # composite provider policy - provider-policy: - type: "COMPOSITE" - authentication: - # first resolve signature, then resolve basic-auth - - name: "http-signatures" - flag: "OPTIONAL" - # must be present - - name: "http-basic-auth" - providers: - # Signatures - - http-signatures: - # only inbound configured, no outbound calls - inbound: - keys: - - key-id: "service1-hmac" - principal-name: "Service1 - HMAC signature" - hmac.secret: "${CLEAR=changeit}" - - key-id: "service1-rsa" - principal-name: "Service1 - RSA signature" - public-key: - keystore: - # path to keystore - resource.path: "src/main/resources/keystore.p12" - # Keystore type - # PKCS12 or JKS - # defaults to jdk default - # keystore-type: "PKCS12" - # password of the keystore - passphrase: "changeit" - # alias of the certificate to get public key from - cert.alias: "service_cert" - # Security provider - basic authentication (supports roles) - - http-basic-auth: - realm: "helidon" - users: - - login: "jack" - password: "${CLEAR=changeit}" - roles: [ "user", "admin" ] - - login: "jill" - password: "${CLEAR=changeit}" - roles: [ "user" ] - - login: "john" - password: "${CLEAR=changeit}" - roles: [] - web-server: - # Configuration of integration with web server - defaults: - authenticate: true - paths: - - path: "/service2" - roles-allowed: [ "user" ] - - path: "/service2-rsa" - roles-allowed: [ "user" ] \ No newline at end of file diff --git a/examples/security/webserver-signatures/src/test/java/io/helidon/examples/security/signatures/SignatureExampleBuilderMainTest.java b/examples/security/webserver-signatures/src/test/java/io/helidon/examples/security/signatures/SignatureExampleBuilderMainTest.java deleted file mode 100644 index e054f19d881..00000000000 --- a/examples/security/webserver-signatures/src/test/java/io/helidon/examples/security/signatures/SignatureExampleBuilderMainTest.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.security.signatures; - -import java.net.URI; - -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; - -/** - * Unit test for {@link SignatureExampleBuilderMain}. - */ -@ServerTest -public class SignatureExampleBuilderMainTest extends SignatureExampleTest { - - protected SignatureExampleBuilderMainTest(WebServer server, URI uri) { - super(server, uri); - } - - @SetUpServer - public static void setup(WebServerConfig.Builder server) { - SignatureExampleBuilderMain.setup(server); - } -} diff --git a/examples/security/webserver-signatures/src/test/java/io/helidon/examples/security/signatures/SignatureExampleConfigMainTest.java b/examples/security/webserver-signatures/src/test/java/io/helidon/examples/security/signatures/SignatureExampleConfigMainTest.java deleted file mode 100644 index e14fab44ada..00000000000 --- a/examples/security/webserver-signatures/src/test/java/io/helidon/examples/security/signatures/SignatureExampleConfigMainTest.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.security.signatures; - -import java.net.URI; - -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; - -/** - * Unit test for {@link SignatureExampleBuilderMain}. - */ -@ServerTest -public class SignatureExampleConfigMainTest extends SignatureExampleTest { - - protected SignatureExampleConfigMainTest(WebServer server, URI uri) { - super(server, uri); - } - - @SetUpServer - public static void setup(WebServerConfig.Builder server) { - SignatureExampleConfigMain.setup(server); - } -} diff --git a/examples/security/webserver-signatures/src/test/java/io/helidon/examples/security/signatures/SignatureExampleTest.java b/examples/security/webserver-signatures/src/test/java/io/helidon/examples/security/signatures/SignatureExampleTest.java deleted file mode 100644 index 16ebbf59818..00000000000 --- a/examples/security/webserver-signatures/src/test/java/io/helidon/examples/security/signatures/SignatureExampleTest.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2018, 2024 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.security.signatures; - -import java.net.URI; -import java.util.Set; - -import io.helidon.security.Security; -import io.helidon.security.providers.httpauth.HttpBasicAuthProvider; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webclient.security.WebClientSecurity; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.testing.junit5.ServerTest; - -import org.junit.jupiter.api.Test; - -import static io.helidon.security.EndpointConfig.PROPERTY_OUTBOUND_ID; -import static io.helidon.security.EndpointConfig.PROPERTY_OUTBOUND_SECRET; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.MatcherAssert.assertThat; - -@ServerTest -public abstract class SignatureExampleTest { - - private final Http1Client client; - - protected SignatureExampleTest(WebServer server, URI uri) { - server.context().register(server); - - Security security = Security.builder() - .addProvider(HttpBasicAuthProvider.builder().build()) - .build(); - - client = Http1Client.builder() - .addService(WebClientSecurity.create(security)) - .baseUri(uri) - .build(); - } - - @Test - public void testService1Hmac() { - test("/service1", Set.of("user", "admin"), Set.of(), "Service1 - HMAC signature"); - } - - @Test - public void testService1Rsa() { - test("/service1-rsa", Set.of("user", "admin"), Set.of(), "Service1 - RSA signature"); - } - - private void test(String uri, Set expectedRoles, Set invalidRoles, String service) { - try (Http1ClientResponse response = client.get(uri) - .property(PROPERTY_OUTBOUND_ID, "jack") - .property(PROPERTY_OUTBOUND_SECRET, "changeit") - .request()) { - - assertThat(response.status().code(), is(200)); - - String payload = response.as(String.class); - - // check login - assertThat(payload, containsString("id='" + "jack" + "'")); - - // check roles - expectedRoles.forEach(role -> assertThat(payload, containsString(":" + role))); - invalidRoles.forEach(role -> assertThat(payload, not(containsString(":" + role)))); - assertThat(payload, containsString("id='" + service + "'")); - } - } -} diff --git a/examples/todo-app/README.md b/examples/todo-app/README.md deleted file mode 100644 index bdaae1f04a8..00000000000 --- a/examples/todo-app/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# TODO Demo Application - -This application implements todomvc[http://todomvc.com] with two microservices -implemented with Helidon MP and Helidon SE. - -## Build - -```shell -mvn clean package -docker build -t helidon-examples-todo-cassandra cassandra -``` - -## Run - -```shell -docker run -d -p 9042:9042 --name helidon-examples-todo-cassandra helidon-examples-todo-cassandra -docker run --name zipkin -d -p 9411:9411 openzipkin/zipkin -java -jar backend/target/helidon-examples-todo-backend.jar & -java -jar frontend/target/helidon-examples-todo-frontend.jar & -``` - -- Open http://localhost:8080 in your browser -- Login with a Google account -- Add some TODO entries -- Check-out the traces at http://localhost:9411 - -### HTTP proxy - -If you want to run behind an HTTP proxy: - -```shell -export security_providers_0_google_dash_login_proxy_dash_host=proxy.acme.com -export security_providers_0_google_dash_login_proxy_dash_port=80 -``` - -## Stop - -```shell -kill %1 %2 -docker rm -f zipkin helidon-examples-todo-cassandra -``` diff --git a/examples/todo-app/backend/pom.xml b/examples/todo-app/backend/pom.xml deleted file mode 100644 index 315aac05604..00000000000 --- a/examples/todo-app/backend/pom.xml +++ /dev/null @@ -1,178 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../applications/mp/pom.xml - - io.helidon.examples.todos - helidon-examples-todo-backend - Helidon Examples TODO Demo Backend - - - Back-end part of the application uses Helidon MP - - - - io.helidon.examples.todos.backend.Main - 3.10.2 - 4.3.1.0 - 4.9.0 - 3.0.2 - 1.32 - 1.19.1 - 1.19.1 - - - - - - com.datastax.cassandra - cassandra-driver-core - ${version.lib.cassandra} - - - io.dropwizard.metrics - metrics-core - - - - - org.yaml - snakeyaml - ${version.snakeyaml.override} - - - org.testcontainers - testcontainers-bom - ${version.testcontainers} - pom - import - - - - - - - io.helidon.microprofile.bundles - helidon-microprofile-core - - - io.helidon.microprofile - helidon-microprofile-security - - - io.helidon.security.providers - helidon-security-providers-google-login - - - io.helidon.security.providers - helidon-security-providers-http-sign - - - io.helidon.security.providers - helidon-security-providers-abac - - - io.helidon.microprofile.tracing - helidon-microprofile-tracing - - - io.helidon.tracing.providers - helidon-tracing-providers-zipkin - - - io.helidon.logging - helidon-logging-jul - runtime - - - com.datastax.cassandra - cassandra-driver-core - - - org.junit.jupiter - junit-jupiter-api - test - - - io.helidon.microprofile.testing - helidon-microprofile-testing-junit5 - test - - - com.datastax.oss - java-driver-core - ${version.datastax.driver} - test - - - com.datastax.oss - java-driver-query-builder - ${version.datastax.driver} - test - - - com.codahale.metrics - metrics-core - ${version.codahale.metrics.core} - test - - - org.testcontainers - junit-jupiter - test - - - org.testcontainers - cassandra - ${version.testcontainers.cassandra} - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/examples/todo-app/backend/src/main/java/io/helidon/examples/todos/backend/DbService.java b/examples/todo-app/backend/src/main/java/io/helidon/examples/todos/backend/DbService.java deleted file mode 100644 index e419f8ee841..00000000000 --- a/examples/todo-app/backend/src/main/java/io/helidon/examples/todos/backend/DbService.java +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.todos.backend; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.function.Supplier; - -import io.helidon.config.Config; -import io.helidon.security.SecurityException; - -import com.datastax.driver.core.BoundStatement; -import com.datastax.driver.core.Cluster; -import com.datastax.driver.core.PreparedStatement; -import com.datastax.driver.core.ResultSet; -import com.datastax.driver.core.Row; -import com.datastax.driver.core.Session; -import io.opentracing.Span; -import io.opentracing.SpanContext; -import io.opentracing.tag.Tags; -import io.opentracing.util.GlobalTracer; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; - -/** - * A service showing to access a no-SQL database. - */ -@ApplicationScoped -public class DbService { - - private static final String LIST_QUERY = "select * from backend where user = ? ALLOW FILTERING"; - private static final String GET_QUERY = "select * from backend where id = ?"; - private static final String INSERT_QUERY = "insert into backend (id, user, message, completed, created)" - + " values (?, ?, ?, ?, ?)"; - private static final String UPDATE_QUERY = "update backend set message = ?, completed = ? where id = ? if user = ?"; - private static final String DELETE_QUERY = "delete from backend where id = ?"; - - private final Session session; - private final PreparedStatement listStatement; - private final PreparedStatement getStatement; - private final PreparedStatement insertStatement; - private final PreparedStatement updateStatement; - private final PreparedStatement deleteStatement; - - /** - * Create a new {@code DbService} instance. - * @param config the configuration root - */ - @Inject - public DbService(Config config) { - Cluster.Builder clusterBuilder = Cluster.builder() - .withoutMetrics(); - - Config cConfig = config.get("cassandra"); - cConfig.get("servers").asList(Config.class).stream() - .flatMap(Collection::stream) - .map(server -> server.get("host").asString().get()) - .forEach(clusterBuilder::addContactPoints); - cConfig.get("port").asInt().ifPresent(clusterBuilder::withPort); - - Cluster cluster = clusterBuilder.build(); - session = cluster.connect("backend"); - - listStatement = session.prepare(LIST_QUERY); - getStatement = session.prepare(GET_QUERY); - insertStatement = session.prepare(INSERT_QUERY); - updateStatement = session.prepare(UPDATE_QUERY); - deleteStatement = session.prepare(DELETE_QUERY); - } - - /** - * Invoke the given supplier and wrap it around with a tracing - * {@code Span}. - * @param the supplier return type - * @param tracingSpan the parent span to use - * @param operation the name of the operation - * @param supplier the supplier to invoke - * @return the object returned by the supplier - */ - private static T execute(SpanContext tracingSpan, String operation, Supplier supplier) { - Span span = startSpan(tracingSpan, operation); - - try { - return supplier.get(); - } catch (Exception e) { - Tags.ERROR.set(span, true); - span.log(Map.of("event", "error", "error.object", e)); - throw e; - } finally { - span.finish(); - } - } - - /** - * Utility method to create and start a child span of the given span. - * @param span the parent span - * @param operation the name for the new span - * @return the created span - */ - private static Span startSpan(SpanContext span, String operation) { - return GlobalTracer.get().buildSpan(operation).asChildOf(span).start(); - } - - /** - * Retrieve the TODOs entries from the database. - * @param tracingSpan the tracing span to use - * @param userId the database user id - * @return retrieved entries as {@code Iterable} - */ - Iterable list(SpanContext tracingSpan, String userId) { - return execute(tracingSpan, "cassandra::list", () -> { - BoundStatement bs = listStatement.bind(userId); - ResultSet rs = session.execute(bs); - - List result = new ArrayList<>(); - for (Row r : rs) { - result.add(Todo.fromDb(r)); - } - - return result; - }); - } - - /** - * Get the entry identified by the given ID from the database. - * @param tracingSpan the tracing span to use - * @param id the ID identifying the entry to retrieve - * @param userId the database user id - * @return retrieved entry as {@code Optional} - */ - Optional get(SpanContext tracingSpan, String id, String userId) { - return execute(tracingSpan, "cassandra::get", () -> getNoContext(id, userId)); - } - - /** - * Get the entry identified by the given ID from the database, fails if the - * entry is not associated with the given {@code userId}. - * @param id the ID identifying the entry to retrieve - * @param userId the database user id - * @return retrieved entry as {@code Optional} - */ - private Optional getNoContext(String id, String userId) { - BoundStatement bs = getStatement.bind(id); - ResultSet rs = session.execute(bs); - Row one = rs.one(); - if (null == one) { - return Optional.empty(); - } - Todo result = Todo.fromDb(one); - if (userId.equals(result.getUserId())) { - return Optional.of(result); - } - throw new SecurityException(String.format( - "User %s attempted to read record %s of another user", - userId, id)); - } - - /** - * Update the given entry in the database. - * @param tracingSpan the tracing span to use - * @param entry the entry to update - * @return {@code Optional} of updated entry if the update was successful, - * otherwise an empty {@code Optional} - */ - Optional update(SpanContext tracingSpan, Todo entry) { - return execute(tracingSpan, "cassandra::update", () -> { - //update backend set message = ? - // , completed = ? where id = ? if user = ? - BoundStatement bs = updateStatement.bind( - entry.getTitle(), - entry.getCompleted(), - entry.getId(), - entry.getUserId()); - ResultSet execute = session.execute(bs); - - if (execute.wasApplied()) { - return Optional.of(entry); - } else { - return Optional.empty(); - } - }); - } - - /** - * Delete the entry identified by the given ID in from the database. - * @param tracingSpan the tracing span to use - * @param id the ID identifying the entry to delete - * @param userId the database user id - * @return the deleted entry as {@code Optional} - */ - Optional delete(SpanContext tracingSpan, String id, String userId) { - return execute(tracingSpan, "cassandra::delete", - () -> getNoContext(id, userId) - .map(todo -> { - BoundStatement bs = deleteStatement.bind(id); - ResultSet rs = session.execute(bs); - if (!rs.wasApplied()) { - throw new RuntimeException("Failed to delete todo: " - + todo); - } - return todo; - })); - } - - /** - * Insert a new entry in the database. - * @param tracingSpan the tracing span to use - * @param entry the entry to insert - */ - void insert(SpanContext tracingSpan, Todo entry) { - execute(tracingSpan, "cassandra::insert", () -> { - BoundStatement bs = insertStatement - .bind(entry.getId(), - entry.getUserId(), - entry.getTitle(), - entry.getCompleted(), - new Date(entry.getCreated())); - - ResultSet execute = session.execute(bs); - if (!execute.wasApplied()) { - throw new RuntimeException("Failed to insert todo: " + entry); - } - return null; - }); - } -} diff --git a/examples/todo-app/backend/src/main/java/io/helidon/examples/todos/backend/JaxRsBackendResource.java b/examples/todo-app/backend/src/main/java/io/helidon/examples/todos/backend/JaxRsBackendResource.java deleted file mode 100644 index 1d420d6bfa5..00000000000 --- a/examples/todo-app/backend/src/main/java/io/helidon/examples/todos/backend/JaxRsBackendResource.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.todos.backend; - -import java.util.Collections; -import java.util.UUID; - -import io.helidon.security.Principal; -import io.helidon.security.SecurityContext; -import io.helidon.security.Subject; -import io.helidon.security.annotations.Authenticated; -import io.helidon.security.annotations.Authorized; - -import io.opentracing.Tracer; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import jakarta.json.Json; -import jakarta.json.JsonArrayBuilder; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -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.Context; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import org.eclipse.microprofile.opentracing.Traced; - -/** - * The TODO backend REST service. - */ -@Path("/api/backend") -@Authenticated -@Authorized -@ApplicationScoped -public class JaxRsBackendResource { - - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - private final DbService backendService; - private final Tracer tracer; - - /** - * Create new {@code JaxRsBackendResource} instance. - * @param dbs the database service facade to use - * @param tracer tracer to use - */ - @Inject - public JaxRsBackendResource(DbService dbs, Tracer tracer) { - this.backendService = dbs; - this.tracer = tracer; - } - - /** - * Retrieve all TODO entries. - * - * @param context security context to map the user - * @return the response with the retrieved entries as entity - */ - @GET - @Produces(MediaType.APPLICATION_JSON) - @Traced(operationName = "jaxrs:list") - public Response list(@Context SecurityContext context) { - JsonArrayBuilder builder = JSON.createArrayBuilder(); - backendService.list(tracer.activeSpan().context(), getUserId(context)) - .forEach(data -> builder.add(data.forRest())); - return Response.ok(builder.build()).build(); - } - - /** - * Get the TODO entry identified by the given ID. - * @param id the ID of the entry to retrieve - * @param context security context to map the user - * @return the response with the retrieved entry as entity - */ - @GET - @Path("/{id}") - @Produces(MediaType.APPLICATION_JSON) - public Response get(@PathParam("id") String id, @Context SecurityContext context) { - return backendService - .get(tracer.activeSpan().context(), id, getUserId(context)) - .map(Todo::forRest) - .map(Response::ok) - .orElse(Response.status(Response.Status.NOT_FOUND)) - .build(); - } - - /** - * Delete the TODO entry identified by the given ID. - * @param id the id of the entry to delete - * @param context security context to map the user - * @return the response with the deleted entry as entity - */ - @DELETE - @Path("/{id}") - @Produces(MediaType.APPLICATION_JSON) - public Response delete(@PathParam("id") String id, @Context SecurityContext context) { - return backendService - .delete(tracer.activeSpan().context(), id, getUserId(context)) - .map(Todo::forRest) - .map(Response::ok) - .orElse(Response.status(Response.Status.NOT_FOUND)) - .build(); - } - - /** - * Create a new TODO entry. - * @param jsonObject the value of the new entry - * @param context security context to map the user - * @return the response ({@code 200} status if successful - */ - @POST - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - public Response createIt(JsonObject jsonObject, @Context SecurityContext context) { - String newId = UUID.randomUUID().toString(); - String userId = getUserId(context); - Todo newBackend = Todo.newTodoFromRest(jsonObject, userId, newId); - - backendService.insert(tracer.activeSpan().context(), newBackend); - - return Response.ok(newBackend.forRest()).build(); - } - - /** - * Update the TODO entry identified by the given ID. - * @param id the ID of the entry to update - * @param jsonObject the updated value of the entry - * @param context security context to map the user - * @return the response with the updated entry as entity - */ - @PUT - @Path("/{id}") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - public Response update(@PathParam("id") String id, JsonObject jsonObject, @Context SecurityContext context) { - return backendService - .update(tracer.activeSpan().context(), Todo.fromRest(jsonObject, getUserId(context), id)) - .map(Todo::forRest) - .map(Response::ok) - .orElse(Response.status(Response.Status.NOT_FOUND)) - .build(); - } - - /** - * Get the user id from the security context. - * @param context the security context - * @return user id found in the context or {@code } otherwise - */ - private String getUserId(SecurityContext context) { - return context.user() - .map(Subject::principal) - .map(Principal::id) - .orElse(""); - } -} diff --git a/examples/todo-app/backend/src/main/java/io/helidon/examples/todos/backend/Main.java b/examples/todo-app/backend/src/main/java/io/helidon/examples/todos/backend/Main.java deleted file mode 100644 index 4b3b29e3f92..00000000000 --- a/examples/todo-app/backend/src/main/java/io/helidon/examples/todos/backend/Main.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.todos.backend; - -import java.util.List; - -import io.helidon.config.Config; -import io.helidon.logging.common.LogConfig; -import io.helidon.microprofile.server.Server; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.environmentVariables; -import static io.helidon.config.ConfigSources.file; - -/** - * Main class to start the service. - */ -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) { - - // load logging configuration - LogConfig.configureRuntime(); - - Config config = buildConfig(); - - // as we need to use custom filter - // we need to build Server with custom config - Server server = Server.builder() - .config(config) - .build(); - - server.start(); - } - - /** - * Load the configuration from all sources. - * @return the configuration root - */ - static Config buildConfig() { - return Config.builder() - .sources(List.of( - environmentVariables(), - // expected on development machine - // to override props for dev - file("dev.yaml").optional(), - // expected in k8s runtime - // to configure testing/production values - file("prod.yaml").optional(), - // in jar file - // (see src/main/resources/application.yaml) - classpath("application.yaml"))) - // support for passwords in configuration - //.addFilter(SecureConfigFilter.fromConfig()) - .build(); - } -} diff --git a/examples/todo-app/backend/src/main/java/io/helidon/examples/todos/backend/Todo.java b/examples/todo-app/backend/src/main/java/io/helidon/examples/todos/backend/Todo.java deleted file mode 100644 index 12128f391b6..00000000000 --- a/examples/todo-app/backend/src/main/java/io/helidon/examples/todos/backend/Todo.java +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.todos.backend; - -import java.time.Instant; -import java.time.format.DateTimeFormatter; -import java.util.Collections; -import java.util.UUID; - -import com.datastax.driver.core.Row; -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonNumber; -import jakarta.json.JsonObject; -import jakarta.json.JsonObjectBuilder; - -/** - * Data object for backend. - */ -public final class Todo { - - /** - * Date formatter to format the dates of the TODO entries. - */ - private static final DateTimeFormatter DATE_FORMAT = - DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSVV"); - - /** - * Factory for creating JSON builders. - */ - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - /** - * The TODO ID. - */ - private String id; - - /** - * The user ID associated with this TODO. - */ - private String userId; - - /** - * The TODO title. - */ - private String title; - - /** - * The TODO completed flag. - */ - private Boolean completed; - - /** - * The TODO creation timestamp. - */ - private long created; - - /** - * Create a new {@code Todo} instance from a database entry in JSON format. - * @param jsonObject the database entry - * @return the created instance - */ - public static Todo fromDb(final JsonObject jsonObject) { - - Todo result = new Todo(); - result.id = jsonObject.getString("id"); - result.userId = jsonObject.getString("user"); - result.title = jsonObject.getString("message"); - result.completed = jsonObject.getBoolean("completed"); - result.created = Instant.from(DATE_FORMAT - .parse(jsonObject.getString("created"))).toEpochMilli(); - return result; - } - - /** - * Create a new {@code Todo} instance from a REST entry. - * The created entry will be new, i.e the {@code completed} flag will be set - * to {@code false} and the {@code created} timestamp set to the current - * time. - * @param jsonObject the REST entry - * @param userId the user ID associated with this entry - * @param id the entry ID - * @return the created instance - */ - public static Todo newTodoFromRest(final JsonObject jsonObject, - final String userId, - final String id) { - - Todo result = new Todo(); - result.id = id; - result.userId = userId; - result.title = jsonObject.getString("title"); - result.completed = jsonObject.getBoolean("completed", false); - result.created = System.currentTimeMillis(); - return result; - } - - /** - * Create a new {@code Todo} instance from a REST entry. - * @param jsonObject the REST entry - * @param userId the user ID associated with this entry - * @param id the entry ID - * @return the created instance - */ - public static Todo fromRest(final JsonObject jsonObject, - final String userId, - final String id) { - - Todo result = new Todo(); - result.id = id; - result.userId = userId; - result.title = jsonObject.getString("title", ""); - result.completed = jsonObject.getBoolean("completed"); - JsonNumber created = jsonObject.getJsonNumber("created"); - if (null != created) { - result.created = created.longValue(); - } - return result; - } - - /** - * Create a new {@code Todo} instance from a database entry. - * @param row the database entry - * @return the created instance - */ - public static Todo fromDb(final Row row) { - - Todo result = new Todo(); - result.id = row.getString("id"); - result.userId = row.getString("user"); - result.title = row.getString("message"); - result.completed = row.getBool("completed"); - result.created = row.getTimestamp("created").getTime(); - return result; - } - - /** - * Create a new {@code Todo} instance. - * The created entry will be new, i.e the {@code completed} flag will be set - * to {@code false} and the {@code created} timestamp set to the current - * time. - * @param userId the user ID associated with the new entry - * @param title the title for the new entry - * @return the created instance - */ - public static Todo create(final String userId, final String title) { - Todo result = new Todo(); - - result.id = UUID.randomUUID().toString(); - result.userId = userId; - result.title = title; - result.completed = false; - result.created = System.currentTimeMillis(); - - return result; - } - - /** - * Convert this {@code Todo} instance to the JSON database format. - * @return {@code JsonObject} - */ - public JsonObject forDb() { - //to store to DB - JsonObjectBuilder builder = JSON.createObjectBuilder(); - return builder.add("id", id) - .add("user", userId) - .add("message", title) - .add("completed", completed) - .add("created", created) - .build(); - } - - /** - * Convert this {@code Todo} instance to the JSON REST format. - * @return {@code JsonObject} - */ - public JsonObject forRest() { - //to send over to rest - JsonObjectBuilder builder = JSON.createObjectBuilder(); - return builder.add("id", id) - .add("user", userId) - .add("title", title) - .add("completed", completed) - .add("created", created) - .build(); - } - - /** - * Get the TODO ID. - * @return the {@code String} identifying this entry - */ - public String getId() { - return id; - } - - /** - * Get the user ID associated with this TODO. - * @return the {@code String} identifying the user - */ - public String getUserId() { - return userId; - } - - /** - * Get the TODO title. - * @return title - */ - public String getTitle() { - return title; - } - - /** - * Get the completed flag. - * @return completed flag. - */ - public Boolean getCompleted() { - return completed; - } - - /** - * Set the completed flag. - * @param iscomplete the completed flag value - */ - public void setCompleted(final boolean iscomplete) { - this.completed = iscomplete; - } - - /** - * Get the creation timestamp. - * @return timestamp - */ - public long getCreated() { - return created; - } - - @Override - public String toString() { - return "Todo{" - + "id='" + id + '\'' - + ", userId='" + userId + '\'' - + ", title='" + title + '\'' - + ", completed=" + completed - + ", created=" + created - + '}'; - } -} diff --git a/examples/todo-app/backend/src/main/java/io/helidon/examples/todos/backend/package-info.java b/examples/todo-app/backend/src/main/java/io/helidon/examples/todos/backend/package-info.java deleted file mode 100644 index 662a11d74f9..00000000000 --- a/examples/todo-app/backend/src/main/java/io/helidon/examples/todos/backend/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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. - */ - -/** - * TODOs Demo application backend. - */ -package io.helidon.examples.todos.backend; diff --git a/examples/todo-app/backend/src/main/resources/META-INF/beans.xml b/examples/todo-app/backend/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 1b3fbc297cb..00000000000 --- a/examples/todo-app/backend/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/examples/todo-app/backend/src/main/resources/application.yaml b/examples/todo-app/backend/src/main/resources/application.yaml deleted file mode 100644 index 8727766ddce..00000000000 --- a/examples/todo-app/backend/src/main/resources/application.yaml +++ /dev/null @@ -1,48 +0,0 @@ -# -# Copyright (c) 2018, 2024 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. -# -env: docker - -server: - port: 8854 - host: 0.0.0.0 - -tracing: - service: "todo:back" - port: 9411 - -cassandra: - port: 9042 - servers: - - host: "localhost" - -security: - config: - require-encryption: false - aes.insecure-passphrase: "changeit" - provider-policy: - type: "COMPOSITE" - authentication: - - name: "google-login" - - name: "http-signatures" - providers: - - google-login: - client-id: "1048216952820-6a6ke9vrbjlhngbc0al0dkj9qs9tqbk2.apps.googleusercontent.com" - - abac: - - http-signatures: - inbound.keys: - - key-id: "frontend" - principal-name: "Frontend Service" - hmac.secret: "${CLEAR=changeit}" diff --git a/examples/todo-app/backend/src/main/resources/logging.properties b/examples/todo-app/backend/src/main/resources/logging.properties deleted file mode 100644 index 3543f0f4e1c..00000000000 --- a/examples/todo-app/backend/src/main/resources/logging.properties +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2017, 2023 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. -# - -#All attributes details -handlers=io.helidon.logging.jul.HelidonConsoleHandler -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 - -#All log level details -.level=WARNING -io.helidon.webserver.level=INFO -io.helidon.security.level=INFO -io.helidon.tracing.level=FINE -AUDIT.level=FINEST - - diff --git a/examples/todo-app/backend/src/test/java/io/helidon/examples/todos/backend/BackendTests.java b/examples/todo-app/backend/src/test/java/io/helidon/examples/todos/backend/BackendTests.java deleted file mode 100644 index e5f0316b75a..00000000000 --- a/examples/todo-app/backend/src/test/java/io/helidon/examples/todos/backend/BackendTests.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (c) 2021, 2024 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.todos.backend; - -import java.util.Base64; -import java.util.Properties; - -import io.helidon.config.mp.MpConfigSources; -import io.helidon.config.yaml.mp.YamlMpConfigSource; -import io.helidon.http.HeaderNames; -import io.helidon.microprofile.testing.junit5.Configuration; -import io.helidon.microprofile.testing.junit5.HelidonTest; - -import com.datastax.driver.core.Cluster; -import com.datastax.driver.core.Session; -import jakarta.inject.Inject; -import jakarta.json.Json; -import jakarta.json.JsonArray; -import jakarta.json.JsonObject; -import jakarta.ws.rs.client.Entity; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.MediaType; -import org.eclipse.microprofile.config.spi.ConfigProviderResolver; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.EnabledOnOs; -import org.junit.jupiter.api.condition.OS; -import org.testcontainers.containers.CassandraContainer; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -@Testcontainers -@HelidonTest -@Configuration(useExisting = true) -@EnabledOnOs(OS.LINUX) // due to usage of docker with testcontainers, only Linux is enabled by default -class BackendTests { - @Container - static final CassandraContainer CASSANDRA_CONTAINER = new CassandraContainer<>("cassandra:3.11.2") - .withReuse(true); - - @Inject - private WebTarget webTarget; - - @BeforeAll - static void init() { - Properties cassandraProperties = initCassandra(); - - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - ConfigProviderResolver configResolver = ConfigProviderResolver.instance(); - - org.eclipse.microprofile.config.Config mpConfig = configResolver.getBuilder() - .withSources(YamlMpConfigSource.create(cl.getResource("test-application.yaml")), - MpConfigSources.create(cassandraProperties)) - .build(); - - configResolver.registerConfig(mpConfig, null); - } - - @AfterAll - static void stopServer() { - } - - private static Properties initCassandra() { - String host = CASSANDRA_CONTAINER.getHost(); - Integer port = CASSANDRA_CONTAINER.getMappedPort(CassandraContainer.CQL_PORT); - - Properties prop = new Properties(); - prop.put("cassandra.port", String.valueOf(port)); - prop.put("cassandra.servers.host.host", host); - - Cluster cluster = Cluster.builder() - .withoutMetrics() - .addContactPoint(host) - .withPort(port) - .build(); - - Session session = cluster.newSession(); - session.execute("CREATE KEYSPACE backend WITH REPLICATION = {'class' : 'SimpleStrategy', 'replication_factor' : 1};"); - session.execute( - "CREATE TABLE backend.backend (id ascii, user ascii, message ascii, completed Boolean, created timestamp, " - + "PRIMARY KEY (id));"); - session.execute("select * from backend.backend;"); - - session.close(); - cluster.close(); - - return prop; - } - - @Test - void testTodoScenario() { - String basicAuth = "Basic " + Base64.getEncoder().encodeToString("john:changeit".getBytes()); - JsonObject todo = Json.createObjectBuilder() - .add("title", "todo title") - .build(); - - // Add a new todo - JsonObject returnedTodo = webTarget - .path("/api/backend") - .request(MediaType.APPLICATION_JSON_TYPE) - .header(HeaderNames.AUTHORIZATION.defaultCase(), basicAuth) - .post(Entity.json(todo), JsonObject.class); - - assertThat(returnedTodo.getString("user"), is("john")); - assertThat(returnedTodo.getString("title"), is(todo.getString("title"))); - - // Get the todo created earlier - JsonObject fromServer = webTarget.path("/api/backend/" + returnedTodo.getString("id")) - .request(MediaType.APPLICATION_JSON_TYPE) - .header(HeaderNames.AUTHORIZATION.defaultCase(), basicAuth) - .get(JsonObject.class); - - assertThat(fromServer, is(returnedTodo)); - - // Update the todo created earlier - JsonObject updatedTodo = Json.createObjectBuilder() - .add("title", "updated title") - .add("completed", false) - .build(); - - fromServer = webTarget.path("/api/backend/" + returnedTodo.getString("id")) - .request(MediaType.APPLICATION_JSON_TYPE) - .header(HeaderNames.AUTHORIZATION.defaultCase(), basicAuth) - .put(Entity.json(updatedTodo), JsonObject.class); - - assertThat(fromServer.getString("title"), is(updatedTodo.getString("title"))); - - // Delete the todo created earlier - fromServer = webTarget.path("/api/backend/" + returnedTodo.getString("id")) - .request(MediaType.APPLICATION_JSON_TYPE) - .header(HeaderNames.AUTHORIZATION.defaultCase(), basicAuth) - .delete(JsonObject.class); - - assertThat(fromServer.getString("id"), is(returnedTodo.getString("id"))); - - // Get list of todos - JsonArray jsonValues = webTarget.path("/api/backend") - .request(MediaType.APPLICATION_JSON_TYPE) - .header(HeaderNames.AUTHORIZATION.defaultCase(), basicAuth) - .get(JsonArray.class); - - assertThat("There should be no todos on server", jsonValues.size(), is(0)); - } - -} diff --git a/examples/todo-app/backend/src/test/resources/test-application.yaml b/examples/todo-app/backend/src/test/resources/test-application.yaml deleted file mode 100644 index 299eed138e7..00000000000 --- a/examples/todo-app/backend/src/test/resources/test-application.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# -# Copyright (c) 2021, 2024 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. -# - -# increase importance -config_ordinal: 500 - -# we use custom config and Helidon JUnit integration, must allow initializer -mp: - initializer: - allow: true - no-warn: true - -server: - port: 0 - host: localhost - -tracing: - service: "todo:back" - enabled: false - -security: - providers: - - http-basic-auth: - realm: "helidon" - users: - - login: "john" - password: "changeit" diff --git a/examples/todo-app/cassandra/Dockerfile b/examples/todo-app/cassandra/Dockerfile deleted file mode 100644 index 81b8c7a5daa..00000000000 --- a/examples/todo-app/cassandra/Dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright (c) 2017, 2023 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. -# - -FROM cassandra:3.11.16 - -ADD startup.sh / - -RUN chmod -v u=rx,og-rwx /startup.sh - -ENTRYPOINT ["/startup.sh"] - -EXPOSE 7000 7001 7199 9042 9160 - -CMD ["cassandra", "-f"] diff --git a/examples/todo-app/cassandra/startup.sh b/examples/todo-app/cassandra/startup.sh deleted file mode 100644 index ca6aaa6d901..00000000000 --- a/examples/todo-app/cassandra/startup.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2017, 2021 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. -# -set -e - -echo 'Starting Cassandra database' -/docker-entrypoint.sh "$@" > /var/log/cassandra.log & - -echo 'Waiting for database to become available' -COUNT='1' -while test $COUNT -lt '120' && ! timeout 1 bash -c 'cat < /dev/null > /dev/tcp/127.0.0.1/9042' > /dev/null 2>&1 ; do - if [ "$((COUNT%10))" -eq '0' ]; then - echo " ...$COUNT s" - fi - sleep 1 - COUNT=$((COUNT+1)) -done - -echo 'Creating todos table' -cqlsh -e " - CREATE KEYSPACE backend WITH REPLICATION = {'class' : 'SimpleStrategy', 'replication_factor' : 1}; - CREATE TABLE backend.backend (id ascii, user ascii, message ascii, completed Boolean, created timestamp, PRIMARY KEY (id)); - select * from backend.backend; -" \ - || true - -echo 'Opening database log file' -echo '-------------------------' -tail -f /var/log/cassandra.log diff --git a/examples/todo-app/frontend/pom.xml b/examples/todo-app/frontend/pom.xml deleted file mode 100644 index 4cacc61aa4c..00000000000 --- a/examples/todo-app/frontend/pom.xml +++ /dev/null @@ -1,173 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.todo - helidon-examples-todo-frontend - Helidon Examples TODO Demo Frontend - - - Front-end part of the application, uses Helidon SE - - - - io.helidon.examples.todos.frontend.Main - ${mainClass} - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver.observe - helidon-webserver-observe - - - io.helidon.webserver - helidon-webserver-security - - - io.helidon.webserver - helidon-webserver-static-content - - - io.helidon.webserver - helidon-webserver-access-log - - - io.helidon.metrics - helidon-metrics-api - - - io.helidon.webserver.observe - helidon-webserver-observe-tracing - - - io.helidon.webclient - helidon-webclient - - - io.helidon.webclient - helidon-webclient-security - - - io.helidon.webclient - helidon-webclient-tracing - - - io.helidon.http.media - helidon-http-media-jsonp - - - io.helidon.common - helidon-common - - - io.helidon.tracing - helidon-tracing - - - io.helidon.tracing.providers - helidon-tracing-providers-zipkin - - - io.helidon.config - helidon-config - - - io.helidon.config - helidon-config-yaml - - - io.helidon.config - helidon-config-encryption - - - io.helidon.security - helidon-security - - - io.helidon.security.providers - helidon-security-providers-google-login - - - io.helidon.security.providers - helidon-security-providers-abac - - - io.helidon.security.providers - helidon-security-providers-http-sign - - - io.helidon.webserver.observe - helidon-webserver-observe-metrics - runtime - - - io.helidon.metrics - helidon-metrics-system-meters - runtime - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - io.helidon.security.providers - helidon-security-providers-http-auth - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/todo-app/frontend/src/main/java/io/helidon/examples/todos/frontend/BackendServiceClient.java b/examples/todo-app/frontend/src/main/java/io/helidon/examples/todos/frontend/BackendServiceClient.java deleted file mode 100644 index 7225e5d689b..00000000000 --- a/examples/todo-app/frontend/src/main/java/io/helidon/examples/todos/frontend/BackendServiceClient.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.todos.frontend; - -import java.net.URI; -import java.util.function.Supplier; - -import io.helidon.common.LazyValue; -import io.helidon.http.HttpException; -import io.helidon.http.Status.Family; -import io.helidon.http.media.jsonp.JsonpSupport; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webclient.security.WebClientSecurity; -import io.helidon.webclient.tracing.WebClientTracing; - -import jakarta.json.JsonArray; -import jakarta.json.JsonObject; - -/** - * Client to invoke the backend service. - */ -final class BackendServiceClient { - - private final LazyValue client = LazyValue.create(this::createClient); - private final Supplier serviceEndpoint; - - BackendServiceClient(Supplier serviceEndpoint) { - this.serviceEndpoint = serviceEndpoint; - } - - private Http1Client createClient() { - return Http1Client.builder() - .servicesDiscoverServices(false) - .addService(WebClientTracing.create()) - .addService(WebClientSecurity.create()) - .addMediaSupport(JsonpSupport.create()) - .baseUri(serviceEndpoint.get().resolve("/api/backend")) - .build(); - } - - private Http1Client client() { - return client.get(); - } - - /** - * Retrieve all entries from the backend. - * - * @return single with all records - */ - JsonArray list() { - return processResponse(client().get().request(), JsonArray.class); - } - - /** - * Retrieve the entry identified by the given ID. - * - * @param id the ID identifying the entry to retrieve - * @return retrieved entry as a {@code JsonObject} - */ - JsonObject get(String id) { - return processResponse(client().get(id).request(), JsonObject.class); - } - - /** - * Delete the entry identified by the given ID. - * - * @param id the ID identifying the entry to delete - * @return deleted entry as a {@code JsonObject} - */ - JsonObject deleteSingle(String id) { - return processResponse(client().delete(id).request(), JsonObject.class); - } - - /** - * Create a new entry. - * - * @param json the new entry value to create as {@code JsonObject} - * @return created entry as {@code JsonObject} - */ - JsonObject create(JsonObject json) { - return processResponse(client().post().submit(json), JsonObject.class); - } - - /** - * Update an entry identified by the given ID. - * - * @param id the ID identifying the entry to update - * @param json the update entry value as {@code JsonObject} - * @return updated entry as {@code JsonObject} - */ - JsonObject update(String id, JsonObject json) { - return processResponse(client().put(id).submit(json), JsonObject.class); - } - - private T processResponse(Http1ClientResponse response, Class clazz) { - if (response.status().family() != Family.SUCCESSFUL) { - throw new HttpException("backend error", response.status()); - } - return response.entity().as(clazz); - } -} diff --git a/examples/todo-app/frontend/src/main/java/io/helidon/examples/todos/frontend/Main.java b/examples/todo-app/frontend/src/main/java/io/helidon/examples/todos/frontend/Main.java deleted file mode 100644 index 56feefd9a6a..00000000000 --- a/examples/todo-app/frontend/src/main/java/io/helidon/examples/todos/frontend/Main.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.todos.frontend; - -import java.net.URI; -import java.util.List; - -import io.helidon.config.Config; -import io.helidon.config.ConfigValue; -import io.helidon.config.FileSystemWatcher; -import io.helidon.http.HeaderNames; -import io.helidon.http.Status; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.staticcontent.StaticContentService; - -import static io.helidon.config.ConfigSources.classpath; -import static io.helidon.config.ConfigSources.environmentVariables; -import static io.helidon.config.ConfigSources.file; -import static io.helidon.config.PollingStrategies.regular; -import static java.time.Duration.ofSeconds; - -/** - * Main class to start the service. - */ -public final class Main { - - private static final Long POLLING_INTERVAL = 5L; - - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * - * @param args command line arguments - */ - public static void main(final String[] args) { - - // load logging configuration - LogConfig.configureRuntime(); - - WebServerConfig.Builder builder = WebServer.builder(); - setup(builder); - WebServer server = builder.build(); - - // start the web server - server.start(); - System.out.println("WEB server is up! http://localhost:" + server.port()); - } - - private static void setup(WebServerConfig.Builder server) { - Config config = buildConfig(); - - ConfigValue backendEndpoint = config.get("services.backend.endpoint").as(URI.class); - - server.config(config.get("server")) - .routing(routing -> routing - // redirect POST / to GET / - .post("/", (req, res) -> { - res.header(HeaderNames.LOCATION, "/"); - res.status(Status.SEE_OTHER_303); - res.send(); - }) - // register static content support (on "/") - .register(StaticContentService.builder("/WEB").welcomeFileName("index.html")) - // register API service (on "/api") - this path is secured (see application.yaml) - .register("/api", new TodoService(new BackendServiceClient(backendEndpoint::get)))); - } - - /** - * Load the configuration from all sources. - * @return the configuration root - */ - private static Config buildConfig() { - return Config.builder() - .sources(List.of( - environmentVariables(), - // expected on development machine - // to override props for dev - file("dev.yaml") - .changeWatcher(FileSystemWatcher.create()) - .optional(), - // expected in k8s runtime - // to configure testing/production values - file("prod.yaml") - .pollingStrategy(regular( - ofSeconds(POLLING_INTERVAL))) - .optional(), - // in jar file - // (see src/main/resources/application.yaml) - classpath("application.yaml"))) - .build(); - } -} diff --git a/examples/todo-app/frontend/src/main/java/io/helidon/examples/todos/frontend/TodoService.java b/examples/todo-app/frontend/src/main/java/io/helidon/examples/todos/frontend/TodoService.java deleted file mode 100644 index c8b3f732e01..00000000000 --- a/examples/todo-app/frontend/src/main/java/io/helidon/examples/todos/frontend/TodoService.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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.todos.frontend; - -import io.helidon.http.Status; -import io.helidon.metrics.api.Counter; -import io.helidon.metrics.api.Meter; -import io.helidon.metrics.api.MeterRegistry; -import io.helidon.metrics.api.Metrics; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -import jakarta.json.JsonObject; - -/** - * TODO service. - *

      - * An entry is structured as follows: - * { 'title': string, 'completed': boolean, 'id': string } - *

      - * The IDs are server generated on the initial POST operation (so they are not - * included in that case). - *

      - * Here is a summary of the operations: - * GET /api/todo: Get all entries - * GET /api/todo/{id}: Get an entry by ID - * POST /api/todo: Create a new entry, created entry is returned - * DELETE /api/todo/{id}: Delete an entry, deleted entry is returned - * PUT /api/todo/{id}: Update an entry, updated entry is returned - */ -public final class TodoService implements HttpService { - - private final BackendServiceClient bsc; - private final Counter createCounter; - private final Counter updateCounter; - private final Counter deleteCounter; - - /** - * Create a new {@code TodosHandler} instance. - * - * @param bsc the {@code BackendServiceClient} to use - */ - TodoService(BackendServiceClient bsc) { - MeterRegistry registry = Metrics.globalRegistry(); - - this.bsc = bsc; - this.createCounter = registry.getOrCreate(Counter.builder("created")); - this.updateCounter = registry.getOrCreate(Counter.builder("updates")); - this.deleteCounter = registry.getOrCreate(counterMetadata("deletes", "Number of deleted todos")); - } - - @Override - public void routing(HttpRules rules) { - rules.get("/todo/{id}", this::get) - .delete("/todo/{id}", this::delete) - .put("/todo/{id}", this::update) - .get("/todo", this::list) - .post("/todo", this::create); - } - - private Counter.Builder counterMetadata(String name, String description) { - return Counter.builder(name) - .description(description) - .baseUnit(Meter.BaseUnits.NONE); - } - - /** - * Handler for {@code POST /todo}. - * - * @param req the server request - * @param res the server response - */ - private void create(ServerRequest req, ServerResponse res) { - JsonObject jsonObject = bsc.create(req.content().as(JsonObject.class)); - createCounter.increment(); - res.status(Status.CREATED_201); - res.send(jsonObject); - } - - /** - * Handler for {@code GET /todo}. - * - * @param req the server request - * @param res the server response - */ - private void list(ServerRequest req, ServerResponse res) { - res.send(bsc.list()); - } - - /** - * Handler for {@code PUT /todo/id}. - * - * @param req the server request - * @param res the server response - */ - private void update(ServerRequest req, ServerResponse res) { - String id = req.path().pathParameters().get("id"); - JsonObject jsonObject = bsc.update(id, req.content().as(JsonObject.class)); - updateCounter.increment(); - res.send(jsonObject); - } - - /** - * Handler for {@code DELETE /todo/id}. - * - * @param req the server request - * @param res the server response - */ - private void delete(ServerRequest req, ServerResponse res) { - String id = req.path().pathParameters().get("id"); - JsonObject jsonObject = bsc.deleteSingle(id); - deleteCounter.increment(); - res.send(jsonObject); - } - - /** - * Handler for {@code GET /todo/id}. - * - * @param req the server request - * @param res the server response - */ - private void get(ServerRequest req, ServerResponse res) { - String id = req.path().pathParameters().get("id"); - res.send(bsc.get(id)); - } -} diff --git a/examples/todo-app/frontend/src/main/java/io/helidon/examples/todos/frontend/package-info.java b/examples/todo-app/frontend/src/main/java/io/helidon/examples/todos/frontend/package-info.java deleted file mode 100644 index e730de0746e..00000000000 --- a/examples/todo-app/frontend/src/main/java/io/helidon/examples/todos/frontend/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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. - */ - -/** - * TODOs Demo application frontend. - */ -package io.helidon.examples.todos.frontend; diff --git a/examples/todo-app/frontend/src/main/resources/WEB/css/styles.css b/examples/todo-app/frontend/src/main/resources/WEB/css/styles.css deleted file mode 100644 index 0a3e16b4e9f..00000000000 --- a/examples/todo-app/frontend/src/main/resources/WEB/css/styles.css +++ /dev/null @@ -1,427 +0,0 @@ -/* - * Copyright (c) 2023 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. - */ - -html, -body { - margin: 0 auto; - padding: 0; - font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif; - line-height: 1.4em; - background: #f5f5f5; - color: #4d4d4d; - min-width: 600px; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - font-weight: 300; -} - -input { - font-family: inherit; - font-weight: inherit; - color: inherit; - border: 0; -} - -button { - margin: 0; - padding: 0; - border: 0; - background: none; - font-size: 100%; - vertical-align: baseline; - font-family: inherit; - font-weight: inherit; - color: inherit; - cursor: pointer; - -webkit-appearance: none; - appearance: none; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -:focus { - outline: 0; -} - -.hidden { - display: none; -} - -nav { - display: flex; - align-items: center; - padding: 0 20px 0 20px; - height: 80px; -} - -.spacer { - flex-grow: 1; -} - -.row { - display: flex; - flex-direction: row; - align-items: center; -} - -.column { - display: flex; - flex-direction: column; - align-items: center; -} - -.wrap { - display: none; -} - -.todoapp { - width: 550px; - background: #fff; - margin: 130px 0 40px 0; - position: relative; - box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), - 0 25px 50px 0 rgba(0, 0, 0, 0.1); -} - -.todoapp input::-webkit-input-placeholder { - font-style: italic; - font-weight: 300; - color: #e6e6e6; -} - -.todoapp input::-moz-placeholder { - font-style: italic; - font-weight: 300; - color: #e6e6e6; -} - -.todoapp h1 { - position: absolute; - top: -155px; - width: 100%; - font-size: 100px; - font-weight: 100; - text-align: center; - color: rgba(175, 47, 47, 0.15); - text-rendering: optimizeLegibility; -} - -.new-todo { - position: relative; - margin: 0; - width: 100%; - font-size: 24px; - font-family: inherit; - font-weight: inherit; - line-height: 1.4em; - color: inherit; - padding: 6px; - border: 1px solid #999; - box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2); - box-sizing: border-box; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.new-todo { - padding: 16px 16px 16px 60px; - border: none; - background: rgba(0, 0, 0, 0.003); - box-shadow: inset 0 -2px 1px rgba(0, 0, 0, 0.03); -} - -.main { - position: relative; - z-index: 2; - border-top: 1px solid #e6e6e6; -} - -.checkbox { - border: none; /* Mobile Safari */ - appearance: none; - opacity: 0.25; - -webkit-appearance: none; - margin: 10px; -} - -.checkbox:after { - font-family: 'Material Symbols Outlined'; - font-size: 25px; - transition: opacity 0.2s ease-out; - cursor: pointer; -} - -.checkbox:hover { - opacity: 0.5; -} - -.checkbox:active { - opacity: 0.75; -} - -.toggle-all:after { - content: "\e877"; -} - -.todo-list { - margin: 0; - padding: 0; - list-style: none; -} - -.todo-list li { - position: relative; - font-size: 24px; - border-bottom: 1px solid #ededed; -} - -.todo-list li:last-child { - border-bottom: none; -} - -.todo-list .view, .todo-list .edit { - flex-grow: 1; - padding: 15px 15px 15px 60px; - line-height: 1.2; - font-size: 24px; -} - -.todo-list li.editing { - padding: 0; -} - -.todo-list li.editing .edit { - display: block; -} - -.todo-list li.editing .view { - display: none; -} - -.todo-list li .toggle { - margin: 10px; - display: flex; - align-items: center; -} - -.toggle:after { - content: "\ef4a"; -} - -.toggle:checked:after { - content: "\e86c"; -} - -.todo-list li label { - word-break: break-all; - padding: 15px 15px 15px 60px; - display: block; - line-height: 1.2; - transition: color 0.4s; -} - -.todo-list li.completed label { - color: #d9d9d9; - text-decoration: line-through; -} - -.todo-list li .actions { - display: flex; - align-items: center; - margin: 10px; -} - -.todo-list li .actions button { - margin: 5px; - opacity: 0.25; - font-size: 0; - cursor: pointer; - transition: opacity 0.2s ease-out; -} - -.todo-list li .actions button:hover { - opacity: 0.5; -} - -.todo-list li .actions button:active { - opacity: 0.75; -} - -.todo-list li .actions button:before { - font-family: 'Material Symbols Outlined'; - font-size: 25px; -} - -.todo-list li .actions .update:before { - content: '\e3c9' -} - -.todo-list li.editing .actions .update:before { - content: '\e5ca' !important; -} - -.todo-list li .actions .delete:before { - content: '\e872' -} - -.todo-list li .edit { - display: none; -} - -.todo-list li.editing:last-child { - margin-bottom: -1px; -} - -.footer { - color: #777; - padding: 10px 15px; - height: 20px; - text-align: center; - border-top: 1px solid #e6e6e6; -} - -.footer:before { - content: ''; - position: absolute; - right: 0; - bottom: 0; - left: 0; - height: 50px; - overflow: hidden; - box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), - 0 8px 0 -3px #f6f6f6, - 0 9px 1px -3px rgba(0, 0, 0, 0.2), - 0 16px 0 -6px #f6f6f6, - 0 17px 2px -6px rgba(0, 0, 0, 0.2); -} - -.todo-count { - float: left; - text-align: left; -} - -.todo-count strong { - font-weight: 300; -} - -.filters { - margin: 0; - padding: 0; - list-style: none; - position: absolute; - right: 0; - left: 0; -} - -.filters li { - display: inline; -} - -.filters li a { - color: inherit; - margin: 3px; - padding: 3px 7px; - text-decoration: none; - border: 1px solid transparent; - border-radius: 3px; -} - -.filters li a:hover { - border-color: rgba(175, 47, 47, 0.1); -} - -.filters li a.selected { - border-color: rgba(175, 47, 47, 0.2); -} - -.clear-completed, html .clear-completed:active { - float: right; - position: relative; - line-height: 20px; - text-decoration: none; - cursor: pointer; -} - -.clear-completed:hover { - text-decoration: underline; -} - -.info { - margin: 0; - color: #bfbfbf; - font-size: 14px; - text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); - text-align: center; -} - -.info p { - line-height: 1; -} - -.info a { - color: inherit; - text-decoration: none; - font-weight: 400; -} - -.info a:hover { - text-decoration: underline; -} - -@media screen and (-webkit-min-device-pixel-ratio: 0) { - .toggle-all, .todo-list li .toggle { - background: none; - } - - .todo-list li .toggle { - height: 40px; - } -} - -@media (max-width: 430px) { - .footer { - height: 50px; - } - - .filters { - bottom: 10px; - } -} - -#user-info { - display:none; -} - -#user-info > div { - display:flex; -} - -#user-info .sign-out { - margin-right: 10px; - background: white; - padding: 5px; - border: 1px solid #dadce0; - border-radius: 4px; - transition: background-color .218s, border-color .218s; -} - -#user-info .sign-out:hover { - border-color: #d2e3fc; - background-color: rgba(66,133,244,.04); -} -#user-info .sign-out:active { - background-color: rgba(66,133,244,.1); -} diff --git a/examples/todo-app/frontend/src/main/resources/WEB/index.html b/examples/todo-app/frontend/src/main/resources/WEB/index.html deleted file mode 100644 index cadce1e3c09..00000000000 --- a/examples/todo-app/frontend/src/main/resources/WEB/index.html +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - Helidon TodoMVC - - - - -

      -
      -
      -
      -
      -

      todos

      -
      - - -
      -
      -
      -
        -
        -
        -
        -
        -
        -

        Helidon implementation of TodoMVC

        -
        -
        - - - - - - - - - diff --git a/examples/todo-app/frontend/src/main/resources/WEB/js/app.js b/examples/todo-app/frontend/src/main/resources/WEB/js/app.js deleted file mode 100644 index 7a4d5ac952d..00000000000 --- a/examples/todo-app/frontend/src/main/resources/WEB/js/app.js +++ /dev/null @@ -1,465 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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. - */ - -/* global jQuery, Router */ - -/** - * @typedef {Object} Handlebars - * @property {function(string, function(*, *, HandlebarsOpts))} registerHelper - * @property {function(HTMLElement):function(object):string} compile - */ - -/** - * @typedef {Object} HandlebarsOpts - * @property {function(object)} fn - * @property {function(object)} inverse - */ - -/** - * @typedef {Object} Google - * @property {GoogleAccount} accounts - */ - -/** - * @typedef {Object} GoogleAccount - * @property {GoogleId} id - */ - -/** - * @typedef {Object} GoogleId - * @property {function({})} initialize - * @property {function()} prompt - * @property {function(Element, Object)} renderButton - * @property {function(string} revoke - */ - -/** - * @typedef {Object} Todo - * @property {string} title - * @property {string=} id - * @property {boolean} completed - */ - -class TodoClient { - - constructor(access_token) { - this.access_token = access_token - } - - /** - * List all entries. - * @return {Promise} - */ - list() { - return this._ajax('GET', '/api/todo'); - } - - /** - * Create a new entry. - * @property {Todo} data - * @return {Promise} - */ - create(item) { - return this._ajax('POST', '/api/todo', item); - } - - /** - * Toggle an entry. - * @param {Todo} item - * @param {boolean} completed - */ - toggle(item, completed) { - const data = {...item, completed}; - return this._ajax('PUT', `/api/todo/${item.id}`, data); - } - - /** - * Update an entry. - * @param {Todo} item - * @return {Promise} - */ - update(item) { - return this._ajax('PUT', `/api/todo/${item.id}`, item); - } - - /** - * Delete an entry. - * @param {string} id - * @return {Promise} - */ - delete(id) { - return this._ajax('DELETE', `/api/todo/${id}`); - } - - /** - * Batch requests. - * @param {Todo[]} items - * @param {function(Todo):boolean} filter - * @param {function(Todo, number): Promise} fn - * @return {Promise[]>} - */ - batch(items, filter, fn) { - const promises = []; - items.forEach((e, i) => { - if (filter(e)) { - promises.push(fn(e, i)); - } - }) - return Promise.all(promises); - } - - /** - * Toggle all items. - * @property {Todo[]} items - * @property {boolean} completed - * @return {Promise} - */ - toggleAll(items, completed) { - const result = [...items]; - return this.batch(items, e => e.completed !== completed, (e, i) => { - return this.toggle(e, completed).then(data => { - result[i] = data; - }) - }).then(() => result); - } - - /** - * Delete all completed items. - * @param {Todo[]} items - * @return {Promise} - */ - deleteCompleted(items) { - const indexes = []; - const result = [...items]; - return this.batch(items, e => e.completed, (data, index) => { - indexes.push(index); - return this._ajax('DELETE', `/api/todo/${data.id}`); - }).then(() => { - indexes.sort(); - for (let i = indexes.length - 1; i >= 0; i--) { - result.splice(indexes[i], 1); - } - return result; - }) - } - - /** - * @param {string} type - * @param {string} path - * @param {object=} data - * @return {Promise} - */ - _ajax(type, path, data) { - while (path.startsWith('/')) { - path = path.substring(1); - } - return new Promise((resolve, reject) => { - // noinspection JSUnusedGlobalSymbols - $.ajax({ - type: type, - beforeSend: (request) => { - if (this.access_token) { - request.setRequestHeader('Authorization', `Bearer ${this.access_token}`); - } - }, - url: window.location.pathname + path, - dataType: 'json', - contentType: 'application/json;charset=utf-8', - data: data && JSON.stringify(data) - }).done((resData) => { - resolve(resData); - }).fail((data, textStatus) => { - reject(textStatus); - }); - }) - } -} - -class App { - - constructor() { - this.client = null; - this.token = null; - this.todos = []; - this.todoTemplate = Handlebars.compile($('#todo-template').html()); - this.footerTemplate = Handlebars.compile($('#footer-template').html()); - this.router = new Router({ - '/:filter': (filter) => { - this.filter = filter; - this.render(); - } - }); - $('.sign-out').on('click', e => this.signOut()); - $('.new-todo').on('keyup', e => this.create(e)); - $('.toggle-all').on('change', e => this.toggleAll(e)); - $('.footer').on('click', '.clear-completed', () => this.deleteCompleted()); - $('.todo-list') - .on('change', '.toggle', e => this.toggle(e)) - .on('click', '.update', e => this.editingMode(e)) - .on('focusout', '.edit', e => this.update(e)) - .on('click', '.delete', e => this.destroy(e)); - } - - signOut() { - const google = /** @type {Google} */ (window['google']); - google.accounts.id.revoke(this.token.sub); - this.client = null; - this.token = null; - $('#user-info').fadeOut(); - $('.wrap').fadeOut(); - google.accounts.id.prompt(); - } - - /** - * Init the application. - */ - init(access_token) { - this.client = new TodoClient(access_token); - this.token = JSON.parse(atob(access_token.split(".")[1])); - const signedIn = access_token && true || false; - if (signedIn) { - this.init0().then(() => { - $('.wrap').fadeIn(); - $('#user-info').fadeIn(); - }) - } - } - - init0() { - return this.client.list().then(items => { - this.todos = items; - this.router.init('/all'); - }).catch(console.error); - } - - /** - * Render. - */ - render() { - const todos = this.getFilteredTodos(); - $('.todo-list').html(this.todoTemplate(todos.map((e, i) => { - e.index = i; - return e; - }))); - $('.main').toggle(todos.length > 0); - $('.toggle-all').prop('checked', this.getActiveTodos().length === 0); - this.renderFooter(); - $('.new-todo').focus(); - } - - /** - * Render the footer. - */ - renderFooter() { - const todoCount = this.todos.length; - const activeTodoCount = this.getActiveTodos().length; - const template = this.footerTemplate({ - activeTodoCount: activeTodoCount, - activeTodoWord: this.pluralize(activeTodoCount, 'item'), - completedTodos: todoCount - activeTodoCount, - filter: this.filter - }); - $('.footer').toggle(todoCount > 0).html(template); - } - - /** - * Pluralize the given word. - * @param {number} count - * @param {string} word - * @return {string} - */ - pluralize(count, word) { - return count === 1 ? word : word + 's'; - } - - /** - * Get the active entries. - * @return {Todo[]} - */ - getActiveTodos() { - return this.todos.filter((todo) => { - return !todo.completed; - }); - } - - /** - * Get the completed entries. - * @return {Todo[]} - */ - getCompletedTodos() { - return this.todos.filter((todo) => todo.completed); - } - - /** - * Get the entries for the current filter. - * @return {Todo[]} - */ - getFilteredTodos() { - if (this.filter === 'active') { - return this.getActiveTodos(); - } - if (this.filter === 'completed') { - return this.getCompletedTodos(); - } - return this.todos; - } - - /** - * Toggle all entries. - * @param {Event} e - */ - toggleAll(e) { - const isChecked = $(e.target).prop('checked'); - this.client.toggleAll(this.todos, isChecked).then(items => { - this.todos = items; - this.render(); - }).catch(console.error); - } - - /** - * Delete all completed entries. - */ - deleteCompleted() { - this.client.deleteCompleted(this.todos).then(items => { - this.todos = items; - this.render(); - }).catch(console.error); - } - - /** - * Create a new entry. - * @param {KeyboardEvent} e - */ - create(e) { - const input = $(e.target); - const val = input.val().trim(); - if (e.key !== "Enter" || !val) { - return; - } - input.val(''); - const item = {title: val, completed: false}; - this.client.create(item).then((data) => { - this.todos.push(data); - this.render(); - }).catch(console.error) - } - - /** - * Toggle an entry. - * @param {Event} e - * @return {Promise} - */ - toggle(e) { - const info = this.entryInfo(e.target); - const entry = this.todos[info.index]; - return this.client.toggle(entry, !entry.completed).then((data) => { - this.todos[info.index] = data; - this.render(); - }).catch(console.error); - } - - /** - * Update an entry. - * @param {{target: Element}} e - * @return {Promise} - */ - update(e) { - const input = $(e.target); - const val = input.val().trim(); - if (!val) { - this.destroy(e); - return Promise.resolve(); - } else { - const info = this.entryInfo(e.target); - const newData = {...this.todos[info.index], title: val}; - return this.client.update(newData).then(data => { - this.todos[info.index] = data; - this.render(); - }).catch(console.error); - } - } - - /** - * Destroy an entry. - * @param {{target: Element}} e - */ - destroy(e) { - const info = this.entryInfo(e.target); - this.client.delete(info.id).then(() => { - this.todos.splice(info.index, 1); - this.render(); - }).catch(console.error); - } - - /** - * Edit an entry. - * @param {Event} e - */ - editingMode(e) { - const listElt = $(e.target).closest('li'); - const editing = listElt.hasClass('editing'); - if (editing) { - const input = listElt.find('.edit'); - this.update({ - target: input[0] - }).then(() => listElt.removeClass('editing')); - } else { - const input = listElt.addClass('editing').find('.edit'); - // puts caret at end of input - const tmpStr = input.val(); - input.val(''); - input.val(tmpStr); - input.focus(); - } - } - - /** - * Get the entry info for an element. - * @param {Element} el - * @return {{index: number, id: string}} - */ - entryInfo(el) { - const id = $(el).closest('li').data('id'); - const todos = this.todos; - let i = todos.length; - while (i--) { - if (todos[i].id === id) { - return {id, index: i}; - } - } - } -} - -window.onload = () => { - const google = /** @type {Google} */ (window['google']); - const Handlebars = /** @type {Handlebars} */ (window['Handlebars']); - - Handlebars.registerHelper('eq', (a, b, options) => { - return a === b ? options.fn(this) : options.inverse(this); - }); - - const app = new App(); - - // noinspection JSUnusedGlobalSymbols,SpellCheckingInspection - google.accounts.id.initialize({ - client_id: '1048216952820-6a6ke9vrbjlhngbc0al0dkj9qs9tqbk2.apps.googleusercontent.com', - auto_select: true, - callback: response => { - app.init(response.credential) - } - }); - google.accounts.id.prompt(); -} diff --git a/examples/todo-app/frontend/src/main/resources/application.yaml b/examples/todo-app/frontend/src/main/resources/application.yaml deleted file mode 100644 index a8cbb7be070..00000000000 --- a/examples/todo-app/frontend/src/main/resources/application.yaml +++ /dev/null @@ -1,63 +0,0 @@ -# -# Copyright (c) 2018, 2024 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. -# -env: docker - -server: - port: 8080 - features: - access-log: - enabled: true - security: - paths: - - path: "/api/{+}" - authenticate: true - -cors: - allow-origins: ["https://cdnjs.cloudflare.com", "https://raw.githubusercontent.com"] - allow-methods: ["GET"] - -tracing: - service: "todo:front" - port: 9411 - -services: - backend.endpoint: "http://localhost:8854" - -security: - config: - require-encryption: false - aes.insecure-passphrase: "changeit" - provider-policy: - type: "COMPOSITE" - authentication: - - name: "google-login" - outbound: - - name: "google-login" - - name: "http-signatures" - providers: - - google-login: - client-id: "1048216952820-6a6ke9vrbjlhngbc0al0dkj9qs9tqbk2.apps.googleusercontent.com" - outbound: - - name: "backend" - hosts: [ "localhost" ] - - abac: - - http-signatures: - outbound: - - name: "backend" - hosts: [ "localhost" ] - signature: - key-id: "frontend" - hmac.secret: "${CLEAR=changeit}" diff --git a/examples/todo-app/frontend/src/main/resources/logging.properties b/examples/todo-app/frontend/src/main/resources/logging.properties deleted file mode 100644 index 3543f0f4e1c..00000000000 --- a/examples/todo-app/frontend/src/main/resources/logging.properties +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2017, 2023 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. -# - -#All attributes details -handlers=io.helidon.logging.jul.HelidonConsoleHandler -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 - -#All log level details -.level=WARNING -io.helidon.webserver.level=INFO -io.helidon.security.level=INFO -io.helidon.tracing.level=FINE -AUDIT.level=FINEST - - diff --git a/examples/todo-app/frontend/src/test/java/io/helidon/examples/todos/frontend/TodoServiceTest.java b/examples/todo-app/frontend/src/test/java/io/helidon/examples/todos/frontend/TodoServiceTest.java deleted file mode 100644 index dc412ca9c37..00000000000 --- a/examples/todo-app/frontend/src/test/java/io/helidon/examples/todos/frontend/TodoServiceTest.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2021, 2024 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.todos.frontend; - -import java.net.URI; -import java.util.Base64; - -import io.helidon.config.Config; -import io.helidon.http.Header; -import io.helidon.http.HeaderNames; -import io.helidon.http.HeaderValues; -import io.helidon.http.Status; -import io.helidon.http.media.jsonp.JsonpSupport; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webclient.security.WebClientSecurity; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; -import io.helidon.webserver.testing.junit5.Socket; - -import jakarta.json.Json; -import jakarta.json.JsonArray; -import jakarta.json.JsonObject; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static io.helidon.config.ConfigSources.classpath; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -@ServerTest -class TodoServiceTest { - - private static final JsonObject TODO = Json.createObjectBuilder().add("msg", "todo").build(); - private static final String ENCODED_ID = Base64.getEncoder().encodeToString("john:changeit".getBytes()); - private static final Header BASIC_AUTH = HeaderValues.create(HeaderNames.AUTHORIZATION, "Basic " + ENCODED_ID); - - private static URI backendUri; - private final Http1Client client; - - TodoServiceTest(URI uri) { - this.client = Http1Client.builder() - .servicesDiscoverServices(false) - .baseUri(uri.resolve("/api/todo")) - .addMediaSupport(JsonpSupport.create()) - .addService(WebClientSecurity.create()) - .addHeader(BASIC_AUTH) - .build(); - } - - static final class BackendServiceMock implements HttpService { - - @Override - public void routing(HttpRules rules) { - rules.get("/", (req, res) -> res.send(Json.createArrayBuilder().add(TODO).build())) - .post((req, res) -> res.send(req.content().as(JsonObject.class))) - .get("/{id}", (req, res) -> res.send(TODO)) - .put("/{id}", (req, res) -> res.send(TODO)) - .delete("/{id}", (req, res) -> res.send(TODO)); - } - } - - @BeforeAll - static void init(@Socket("backend") URI uri) { - backendUri = uri; - } - - @SetUpServer - static void setup(WebServerConfig.Builder server) { - Config config = Config.create(classpath("application-test.yaml")); - - server.config(config.get("server")) - .routing(routing -> routing - .register("/api", new TodoService(new BackendServiceClient(() -> backendUri)))) - .putSocket("backend", socket -> socket - .routing(routing -> routing - .register("/api/backend", new BackendServiceMock()))); - } - - @Test - void testList() { - try (Http1ClientResponse response = client.get().request()) { - assertThat(response.status(), is(Status.OK_200)); - assertThat(response.as(JsonArray.class).getJsonObject(0), is(TODO)); - } - } - - @Test - void testCreate() { - try (Http1ClientResponse response = client.post().submit(TODO)) { - assertThat(response.status(), is(Status.CREATED_201)); - assertThat(response.as(JsonObject.class), is(TODO)); - } - } - - @Test - void testGet() { - try (Http1ClientResponse response = client.get("1").request()) { - assertThat(response.status(), is(Status.OK_200)); - assertThat(response.as(JsonObject.class), is(TODO)); - } - } - - @Test - void testDelete() { - try (Http1ClientResponse response = client.delete("1").request()) { - assertThat(response.status(), is(Status.OK_200)); - assertThat(response.as(JsonObject.class), is(TODO)); - } - } - - @Test - void testUpdate() { - try (Http1ClientResponse response = client.put("1").submit(TODO)) { - assertThat(response.status(), is(Status.OK_200)); - assertThat(response.as(JsonObject.class), is(TODO)); - } - } -} diff --git a/examples/todo-app/frontend/src/test/resources/application-test.yaml b/examples/todo-app/frontend/src/test/resources/application-test.yaml deleted file mode 100644 index cfc65f4c8dd..00000000000 --- a/examples/todo-app/frontend/src/test/resources/application-test.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# -# Copyright (c) 2021, 2024 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: 0 - features: - security: - paths: - - path: "/api/{+}" - authenticate: true - -security: - providers: - - http-basic-auth: - realm: "helidon" - users: - - login: "john" - password: "changeit" diff --git a/examples/todo-app/pom.xml b/examples/todo-app/pom.xml deleted file mode 100644 index f7391508a41..00000000000 --- a/examples/todo-app/pom.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples - helidon-examples-project - 4.1.0-SNAPSHOT - - - io.helidon.examples.todos - example-todo-app-project - pom - 4.1.0-SNAPSHOT - Helidon Examples TODO Demo - - - TODO demo application - - - - frontend - backend - - diff --git a/examples/translator-app/README.md b/examples/translator-app/README.md deleted file mode 100644 index e1eea473801..00000000000 --- a/examples/translator-app/README.md +++ /dev/null @@ -1,84 +0,0 @@ -# Translator Example Application - -This application demonstrates a pseudo application composed of two microservices - implemented with Helidon SE. - -## Start Zipkin - -With Docker: -```shell -docker run --name zipkin -d -p 9411:9411 openzipkin/zipkin -``` - -```shell -curl -sSL https://zipkin.io/quickstart.sh | bash -s -java -jar zipkin.jar -``` - -With Kubernetes: -```shell -kubectl apply \ - -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/ingress-nginx-3.15.2/deploy/static/provider/cloud/deploy.yaml \ - -f ../k8s/zipkin.yaml -``` - -## Build and run - -With Docker: -```shell -docker build -t helidon-examples-translator-backend backend/ -docker build -t helidon-examples-translator-frontend frontend/ -docker run --rm -d -p 9080:9080 \ - --link zipkin \ - --name helidon-examples-translator-backend \ - helidon-examples-translator-backend:latest -docker run --rm -d -p 8080:8080 \ - --link zipkin \ - --link helidon-examples-translator-backend \ - --name helidon-examples-translator-frontend \ - helidon-examples-translator-frontend:latest -``` - -```shell -mvn package -java -jar backend/target/helidon-examples-translator-backend.jar & -java -jar frontend/target/helidon-examples-translator-frontend.jar -``` - -Try the endpoint: -```shell -curl "http://localhost:8080?q=cloud&lang=czech" -curl "http://localhost:8080?q=cloud&lang=french" -curl "http://localhost:8080?q=cloud&lang=italian" -``` - -Then check out the traces at http://localhost:9411. - -## Run with Kubernetes (docker for desktop) - -```shell -docker build -t helidon-examples-translator-backend backend/ -docker build -t helidon-examples-translator-frontend frontend/ -kubectl apply -f backend/app.yaml -f frontend/app.yaml -``` - -Try the endpoint: -```shell -curl "http://localhost/translator?q=cloud&lang=czech" -curl "http://localhost/translator?q=cloud&lang=french" -curl "http://localhost/translator?q=cloud&lang=italian" -``` - -Then check out the traces at http://localhost/zipkin. - -Stop the docker containers: -```shell -docker stop zipkin \ - helidon-examples-translator-backend \ - helidon-examples-translator-frontend -``` - -Delete the Kubernetes resources: -```shell -kubectl delete -f backend/app.yaml -f frontend/app.yaml -``` \ No newline at end of file diff --git a/examples/translator-app/backend/Dockerfile b/examples/translator-app/backend/Dockerfile deleted file mode 100644 index 2b7da084204..00000000000 --- a/examples/translator-app/backend/Dockerfile +++ /dev/null @@ -1,56 +0,0 @@ -# -# Copyright (c) 2018, 2024 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. -# - -# 1st stage, build the app -FROM container-registry.oracle.com/java/jdk-no-fee-term:21 as build - -# Install maven -WORKDIR /usr/share -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 -Dmaven.test.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 container-registry.oracle.com/java/jdk-no-fee-term:21 -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/helidon-examples-translator-backend.jar ./ -COPY --from=build /helidon/target/libs ./libs - -ENV tracing.host="zipkin" - -CMD ["java", "-jar", "helidon-examples-translator-backend.jar"] - -EXPOSE 9080 diff --git a/examples/translator-app/backend/app.yaml b/examples/translator-app/backend/app.yaml deleted file mode 100644 index 8b5b06b3389..00000000000 --- a/examples/translator-app/backend/app.yaml +++ /dev/null @@ -1,54 +0,0 @@ -# -# Copyright (c) 2017, 2021 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. -# - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: helidon-examples-translator-backend - labels: - app: helidon-examples-translator-backend -spec: - replicas: 1 - template: - metadata: - labels: - app: helidon-examples-translator-backend - spec: - containers: - - name: helidon-examples-translator-backend - image: helidon-examples-translator-backend:latest - imagePullPolicy: IfNotPresent - ports: - - containerPort: 9080 - env: - - name: tracing.host - value: zipkin ---- - -apiVersion: v1 -kind: Service -metadata: - name: helidon-examples-translator-backend - labels: - app: helidon-examples-translator-backend -spec: - type: ClusterIP - selector: - app: helidon-examples-translator-backend - ports: - - port: 9080 - targetPort: 9080 - name: http diff --git a/examples/translator-app/backend/pom.xml b/examples/translator-app/backend/pom.xml deleted file mode 100644 index 33a21820683..00000000000 --- a/examples/translator-app/backend/pom.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.translator - helidon-examples-translator-backend - Helidon Examples Translator Backend - - - A translator backend example app. - - - - io.helidon.examples.translator.backend.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.config - helidon-config - - - io.helidon.tracing.providers - helidon-tracing-providers-zipkin - - - io.helidon.webserver.observe - helidon-webserver-observe-tracing - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/translator-app/backend/src/main/java/io/helidon/examples/translator/backend/Main.java b/examples/translator-app/backend/src/main/java/io/helidon/examples/translator/backend/Main.java deleted file mode 100644 index 86214521307..00000000000 --- a/examples/translator-app/backend/src/main/java/io/helidon/examples/translator/backend/Main.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.translator.backend; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.logging.common.LogConfig; -import io.helidon.tracing.Tracer; -import io.helidon.tracing.TracerBuilder; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.observe.ObserveFeature; -import io.helidon.webserver.observe.tracing.TracingObserver; - -/** - * Translator application backend main class. - */ -public class Main { - - private Main() { - } - - static void setup(WebServerConfig.Builder server) { - Config config = Config.builder() - .sources(ConfigSources.environmentVariables()) - .build(); - - Tracer tracer = TracerBuilder.create(config.get("tracing")) - .serviceName("helidon-webserver-translator-backend") - .build(); - - server.port(9080) - .addFeature(ObserveFeature.builder() - .addObserver(TracingObserver.create(tracer)) - .build()) - .routing(routing -> routing - .register(new TranslatorBackendService())); - } - - /** - * The main method of Translator backend. - * - * @param args command-line args, currently ignored. - */ - public static void main(String[] args) { - // configure logging in order to not have the standard JVM defaults - LogConfig.configureRuntime(); - - WebServerConfig.Builder builder = WebServer.builder(); - setup(builder); - WebServer server = builder.build().start(); - - System.out.println("WEB server is up! http://localhost:" + server.port()); - } -} diff --git a/examples/translator-app/backend/src/main/java/io/helidon/examples/translator/backend/TranslatorBackendService.java b/examples/translator-app/backend/src/main/java/io/helidon/examples/translator/backend/TranslatorBackendService.java deleted file mode 100644 index 08de0ae432a..00000000000 --- a/examples/translator-app/backend/src/main/java/io/helidon/examples/translator/backend/TranslatorBackendService.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.translator.backend; - -import java.util.HashMap; -import java.util.Map; - -import io.helidon.http.BadRequestException; -import io.helidon.http.NotFoundException; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -/** - * Translator backend service. - */ -@SuppressWarnings("SpellCheckingInspection") -public class TranslatorBackendService implements HttpService { - - private static final String CZECH = "czech"; - private static final String SPANISH = "spanish"; - private static final String CHINESE = "chinese"; - private static final String HINDI = "hindi"; - private static final String ITALIAN = "italian"; - private static final String FRENCH = "french"; - - private static final String SEPARATOR = "."; - private static final Map TRANSLATED_WORDS_REPOSITORY = new HashMap<>(); - - static { - //translation for word "cloud" - TRANSLATED_WORDS_REPOSITORY.put("cloud" + SEPARATOR + CZECH, "oblak"); - TRANSLATED_WORDS_REPOSITORY.put("cloud" + SEPARATOR + SPANISH, "nube"); - TRANSLATED_WORDS_REPOSITORY.put("cloud" + SEPARATOR + CHINESE, "云"); - TRANSLATED_WORDS_REPOSITORY.put("cloud" + SEPARATOR + HINDI, "बादल"); - TRANSLATED_WORDS_REPOSITORY.put("cloud" + SEPARATOR + ITALIAN, "nube"); - TRANSLATED_WORDS_REPOSITORY.put("cloud" + SEPARATOR + FRENCH, "nuage"); - - //one two three four five six seven eight nine ten - //jedna dvě tři čtyři pět šest sedm osm devět deset - //uno dos tres cuatro cinco seis siete ocho nueve diez - //一二三四五六七八九十 - //एक दो तीन चार पांच छ सात आठ नौ दस - // uno due tre quattro cinque sei sette otto nove dieci - // un deux trois quatre cinq six sept huit neuf dix - - //translation for word "one" - TRANSLATED_WORDS_REPOSITORY.put("one" + SEPARATOR + CZECH, "jedna"); - TRANSLATED_WORDS_REPOSITORY.put("one" + SEPARATOR + SPANISH, "uno"); - TRANSLATED_WORDS_REPOSITORY.put("one" + SEPARATOR + CHINESE, "一"); - TRANSLATED_WORDS_REPOSITORY.put("one" + SEPARATOR + HINDI, "एक"); - TRANSLATED_WORDS_REPOSITORY.put("one" + SEPARATOR + ITALIAN, "uno"); - TRANSLATED_WORDS_REPOSITORY.put("one" + SEPARATOR + FRENCH, "un"); - //translation for word "two" - TRANSLATED_WORDS_REPOSITORY.put("two" + SEPARATOR + CZECH, "dvě"); - TRANSLATED_WORDS_REPOSITORY.put("two" + SEPARATOR + SPANISH, "dos"); - TRANSLATED_WORDS_REPOSITORY.put("two" + SEPARATOR + CHINESE, "二"); - TRANSLATED_WORDS_REPOSITORY.put("two" + SEPARATOR + HINDI, "दो"); - TRANSLATED_WORDS_REPOSITORY.put("two" + SEPARATOR + ITALIAN, "due"); - TRANSLATED_WORDS_REPOSITORY.put("two" + SEPARATOR + FRENCH, "deux"); - //translation for word "three" - TRANSLATED_WORDS_REPOSITORY.put("three" + SEPARATOR + CZECH, "tři"); - TRANSLATED_WORDS_REPOSITORY.put("three" + SEPARATOR + SPANISH, "tres"); - TRANSLATED_WORDS_REPOSITORY.put("three" + SEPARATOR + CHINESE, "三"); - TRANSLATED_WORDS_REPOSITORY.put("three" + SEPARATOR + HINDI, "तीन"); - TRANSLATED_WORDS_REPOSITORY.put("three" + SEPARATOR + ITALIAN, "tre"); - TRANSLATED_WORDS_REPOSITORY.put("three" + SEPARATOR + FRENCH, "trois"); - //translation for word "four" - TRANSLATED_WORDS_REPOSITORY.put("four" + SEPARATOR + CZECH, "čtyři"); - TRANSLATED_WORDS_REPOSITORY.put("four" + SEPARATOR + SPANISH, "cuatro"); - TRANSLATED_WORDS_REPOSITORY.put("four" + SEPARATOR + CHINESE, "四"); - TRANSLATED_WORDS_REPOSITORY.put("four" + SEPARATOR + HINDI, "चार"); - TRANSLATED_WORDS_REPOSITORY.put("four" + SEPARATOR + ITALIAN, "quattro"); - TRANSLATED_WORDS_REPOSITORY.put("four" + SEPARATOR + FRENCH, "quatre"); - //translation for word "five" - TRANSLATED_WORDS_REPOSITORY.put("five" + SEPARATOR + CZECH, "pět"); - TRANSLATED_WORDS_REPOSITORY.put("five" + SEPARATOR + SPANISH, "cinco"); - TRANSLATED_WORDS_REPOSITORY.put("five" + SEPARATOR + CHINESE, "五"); - TRANSLATED_WORDS_REPOSITORY.put("five" + SEPARATOR + HINDI, "पांच"); - TRANSLATED_WORDS_REPOSITORY.put("five" + SEPARATOR + ITALIAN, "cinque"); - TRANSLATED_WORDS_REPOSITORY.put("five" + SEPARATOR + FRENCH, "cinq"); - //translation for word "six" - TRANSLATED_WORDS_REPOSITORY.put("six" + SEPARATOR + CZECH, "šest"); - TRANSLATED_WORDS_REPOSITORY.put("six" + SEPARATOR + SPANISH, "seis"); - TRANSLATED_WORDS_REPOSITORY.put("six" + SEPARATOR + CHINESE, "六"); - TRANSLATED_WORDS_REPOSITORY.put("six" + SEPARATOR + HINDI, "छ"); - TRANSLATED_WORDS_REPOSITORY.put("six" + SEPARATOR + ITALIAN, "sei"); - TRANSLATED_WORDS_REPOSITORY.put("six" + SEPARATOR + FRENCH, "six"); - //translation for word "seven" - TRANSLATED_WORDS_REPOSITORY.put("seven" + SEPARATOR + CZECH, "sedm"); - TRANSLATED_WORDS_REPOSITORY.put("seven" + SEPARATOR + SPANISH, "siete"); - TRANSLATED_WORDS_REPOSITORY.put("seven" + SEPARATOR + CHINESE, "七"); - TRANSLATED_WORDS_REPOSITORY.put("seven" + SEPARATOR + HINDI, "सात"); - TRANSLATED_WORDS_REPOSITORY.put("seven" + SEPARATOR + ITALIAN, "sette"); - TRANSLATED_WORDS_REPOSITORY.put("seven" + SEPARATOR + FRENCH, "sept"); - //translation for word "eight" - TRANSLATED_WORDS_REPOSITORY.put("eight" + SEPARATOR + CZECH, "osm"); - TRANSLATED_WORDS_REPOSITORY.put("eight" + SEPARATOR + SPANISH, "ocho"); - TRANSLATED_WORDS_REPOSITORY.put("eight" + SEPARATOR + CHINESE, "八"); - TRANSLATED_WORDS_REPOSITORY.put("eight" + SEPARATOR + HINDI, "आठ"); - TRANSLATED_WORDS_REPOSITORY.put("eight" + SEPARATOR + ITALIAN, "otto"); - TRANSLATED_WORDS_REPOSITORY.put("eight" + SEPARATOR + FRENCH, "huit"); - //translation for word "nine" - TRANSLATED_WORDS_REPOSITORY.put("nine" + SEPARATOR + CZECH, "devět"); - TRANSLATED_WORDS_REPOSITORY.put("nine" + SEPARATOR + SPANISH, "nueve"); - TRANSLATED_WORDS_REPOSITORY.put("nine" + SEPARATOR + CHINESE, "九"); - TRANSLATED_WORDS_REPOSITORY.put("nine" + SEPARATOR + HINDI, "नौ"); - TRANSLATED_WORDS_REPOSITORY.put("nine" + SEPARATOR + ITALIAN, "nove"); - TRANSLATED_WORDS_REPOSITORY.put("nine" + SEPARATOR + FRENCH, "neuf"); - //translation for word "ten" - TRANSLATED_WORDS_REPOSITORY.put("ten" + SEPARATOR + CZECH, "deset"); - TRANSLATED_WORDS_REPOSITORY.put("ten" + SEPARATOR + SPANISH, "diez"); - TRANSLATED_WORDS_REPOSITORY.put("ten" + SEPARATOR + CHINESE, "十"); - TRANSLATED_WORDS_REPOSITORY.put("ten" + SEPARATOR + HINDI, "दस"); - TRANSLATED_WORDS_REPOSITORY.put("ten" + SEPARATOR + ITALIAN, "dieci"); - TRANSLATED_WORDS_REPOSITORY.put("ten" + SEPARATOR + FRENCH, "dix"); - } - - @Override - public void routing(HttpRules rules) { - rules.get(this::getText); - } - - private void getText(ServerRequest req, ServerResponse res) { - - String query = req.query().first("q") - .orElseThrow(() -> new BadRequestException("missing query parameter 'q'")); - String language = req.query().first("lang") - .orElseThrow(() -> new BadRequestException("missing query parameter 'lang'")); - String translation; - translation = switch (language) { - case CZECH -> TRANSLATED_WORDS_REPOSITORY.get(query + SEPARATOR + CZECH); - case SPANISH -> TRANSLATED_WORDS_REPOSITORY.get(query + SEPARATOR + SPANISH); - case CHINESE -> TRANSLATED_WORDS_REPOSITORY.get(query + SEPARATOR + CHINESE); - case HINDI -> TRANSLATED_WORDS_REPOSITORY.get(query + SEPARATOR + HINDI); - case ITALIAN -> TRANSLATED_WORDS_REPOSITORY.get(query + SEPARATOR + ITALIAN); - case FRENCH -> TRANSLATED_WORDS_REPOSITORY.get(query + SEPARATOR + FRENCH); - default -> throw new NotFoundException(String.format( - "Language '%s' not in supported. Supported languages: %s, %s, %s, %s.", - language, - CZECH, SPANISH, CHINESE, HINDI)); - }; - - if (translation != null) { - res.send(translation); - } else { - res.status(404) - .send(String.format("Word '%s' not in the dictionary", query)); - } - } -} diff --git a/examples/translator-app/backend/src/main/java/io/helidon/examples/translator/backend/package-info.java b/examples/translator-app/backend/src/main/java/io/helidon/examples/translator/backend/package-info.java deleted file mode 100644 index b73bbaa5690..00000000000 --- a/examples/translator-app/backend/src/main/java/io/helidon/examples/translator/backend/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2017, 2021 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. - */ - -/** - * Demo examples Translator Backend package. - */ -package io.helidon.examples.translator.backend; diff --git a/examples/translator-app/backend/src/main/resources/logging.properties b/examples/translator-app/backend/src/main/resources/logging.properties deleted file mode 100644 index f5eaea51888..00000000000 --- a/examples/translator-app/backend/src/main/resources/logging.properties +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2017, 2023 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. -# - - -#All attributes details -handlers=io.helidon.logging.jul.HelidonConsoleHandler -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 - -#All log level details -.level=INFO - -io.helidon.webserver.level=FINEST -org.glassfish.jersey.internal.Errors.level=SEVERE diff --git a/examples/translator-app/frontend/Dockerfile b/examples/translator-app/frontend/Dockerfile deleted file mode 100644 index d28e9c54526..00000000000 --- a/examples/translator-app/frontend/Dockerfile +++ /dev/null @@ -1,57 +0,0 @@ -# -# Copyright (c) 2018, 2024 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. -# - -# 1st stage, build the app -FROM container-registry.oracle.com/java/jdk-no-fee-term:21 as build - -# Install maven -WORKDIR /usr/share -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 -Dmaven.test.skip - -# Do the Maven build! -# Incremental docker builds will resume here when you change sources -ADD src src -RUN mvn package -Dmaven.test.skip - -RUN echo "done!" - -# 2nd stage, build the runtime image -FROM container-registry.oracle.com/java/jdk-no-fee-term:21 -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/helidon-examples-translator-frontend.jar ./ -COPY --from=build /helidon/target/libs ./libs - -ENV tracing.host="zipkin" -ENV backend.host="helidon-examples-translator-backend" - -CMD ["java", "-jar", "helidon-examples-translator-frontend.jar"] - -EXPOSE 8080 diff --git a/examples/translator-app/frontend/app.yaml b/examples/translator-app/frontend/app.yaml deleted file mode 100644 index c9359dd25b2..00000000000 --- a/examples/translator-app/frontend/app.yaml +++ /dev/null @@ -1,76 +0,0 @@ -# -# Copyright (c) 2017, 2021 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. -# - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: helidon-examples-translator-frontend - labels: - app: helidon-examples-translator-frontend -spec: - replicas: 1 - template: - metadata: - labels: - app: helidon-examples-translator-frontend - spec: - containers: - - name: translator-frontend - image: helidon-examples-translator-frontend:latest - imagePullPolicy: IfNotPresent - ports: - - containerPort: 8080 - env: - - name: tracing.host - value: zipkin - - name: backend.host - value: helidon-examples-translator-backend - ---- - -apiVersion: v1 -kind: Service -metadata: - name: helidon-examples-translator-frontend - labels: - app: helidon-examples-translator-frontend -spec: - type: ClusterIP - ports: - - name: http - port: 8080 - selector: - app: helidon-examples-translator-frontend - sessionAffinity: None - ---- - -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: helidon-examples-translator-frontend -spec: - rules: - - host: localhost - http: - paths: - - path: /translator - pathType: Prefix - backend: - service: - name: helidon-examples-translator-frontend - port: - number: 8080 diff --git a/examples/translator-app/frontend/pom.xml b/examples/translator-app/frontend/pom.xml deleted file mode 100644 index 01434852475..00000000000 --- a/examples/translator-app/frontend/pom.xml +++ /dev/null @@ -1,121 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.translator - helidon-examples-translator-frontend - Helidon Examples Translator Frontend - - - A translator frontend example app. - - - - io.helidon.examples.translator.frontend.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver.observe - helidon-webserver-observe-tracing - - - io.helidon.webclient - helidon-webclient - - - io.helidon.config - helidon-config - - - io.helidon.tracing.providers - helidon-tracing-providers-zipkin - - - io.helidon.common - helidon-common - - - io.helidon.logging - helidon-logging-jul - runtime - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - - - - add-backend-dependency - - - !maven.test.skip - - - - - io.helidon.examples.translator - helidon-examples-translator-backend - ${project.version} - test - - - - - diff --git a/examples/translator-app/frontend/src/main/java/io/helidon/examples/translator/frontend/Main.java b/examples/translator-app/frontend/src/main/java/io/helidon/examples/translator/frontend/Main.java deleted file mode 100644 index 4e5d71b74d0..00000000000 --- a/examples/translator-app/frontend/src/main/java/io/helidon/examples/translator/frontend/Main.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.translator.frontend; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.logging.common.LogConfig; -import io.helidon.tracing.Tracer; -import io.helidon.tracing.TracerBuilder; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.observe.ObserveFeature; -import io.helidon.webserver.observe.tracing.TracingObserver; - -/** - * Translator application frontend main class. - */ -public class Main { - - private Main() { - } - - /** - * The main method of Translator frontend. - * - * @param args command-line args, currently ignored. - */ - public static void main(String[] args) { - // configure logging in order to not have the standard JVM defaults - LogConfig.configureRuntime(); - - WebServerConfig.Builder builder = WebServer.builder(); - setup(builder); - WebServer server = builder.build().start(); - - System.out.println("WEB server is up! http://localhost:" + server.port()); - } - - static void setup(WebServerConfig.Builder server) { - Config config = Config.builder() - .sources(ConfigSources.environmentVariables()) - .build(); - - Tracer tracer = TracerBuilder.create(config.get("tracing")) - .serviceName("helidon-webserver-translator-frontend") - .registerGlobal(false) - .build(); - String backendHost = config.get("backend.host").asString().orElse("localhost"); - server.addFeature(ObserveFeature.builder() - .addObserver(TracingObserver.create(tracer)) - .build()) - .routing(routing -> routing - .register(new TranslatorFrontendService(backendHost, 9080))); - } -} diff --git a/examples/translator-app/frontend/src/main/java/io/helidon/examples/translator/frontend/TranslatorFrontendService.java b/examples/translator-app/frontend/src/main/java/io/helidon/examples/translator/frontend/TranslatorFrontendService.java deleted file mode 100644 index 0569de9a905..00000000000 --- a/examples/translator-app/frontend/src/main/java/io/helidon/examples/translator/frontend/TranslatorFrontendService.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.translator.frontend; - -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.helidon.http.BadRequestException; -import io.helidon.http.Status; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -/** - * Translator frontend resource. - */ -public final class TranslatorFrontendService implements HttpService { - - private static final Logger LOGGER = Logger.getLogger(TranslatorFrontendService.class.getName()); - private final Http1Client client; - - /** - * Create a new instance. - * - * @param backendHostname backend service host - * @param backendPort backend service port - */ - public TranslatorFrontendService(String backendHostname, int backendPort) { - client = Http1Client.builder() - .baseUri("http://" + backendHostname + ":" + backendPort) - .build(); - } - - @Override - public void routing(HttpRules rules) { - rules.get(this::getText); - } - - private void getText(ServerRequest re, ServerResponse res) { - try { - String query = re.query() - .first("q") - .orElseThrow(() -> new BadRequestException("missing query parameter 'q'")); - - String language = re.query() - .first("lang") - .orElseThrow(() -> new BadRequestException("missing query parameter 'lang'")); - - try (Http1ClientResponse clientRes = client.get() - .queryParam("q", query) - .queryParam("lang", language) - .request()) { - - final String result; - if (clientRes.status().family() == Status.Family.SUCCESSFUL) { - result = clientRes.entity().as(String.class); - } else { - result = "Error: " + clientRes.entity().as(String.class); - } - res.send(result + "\n"); - } - } catch (RuntimeException pe) { - LOGGER.log(Level.WARNING, "Problem to call translator frontend.", pe); - res.status(503).send("Translator backend service isn't available."); - } - } -} diff --git a/examples/translator-app/frontend/src/main/java/io/helidon/examples/translator/frontend/package-info.java b/examples/translator-app/frontend/src/main/java/io/helidon/examples/translator/frontend/package-info.java deleted file mode 100644 index 4729f81fc50..00000000000 --- a/examples/translator-app/frontend/src/main/java/io/helidon/examples/translator/frontend/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2017, 2021 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. - */ - -/** - * Demo examples Translator Frontend package. - */ -package io.helidon.examples.translator.frontend; diff --git a/examples/translator-app/frontend/src/main/resources/logging.properties b/examples/translator-app/frontend/src/main/resources/logging.properties deleted file mode 100644 index f5eaea51888..00000000000 --- a/examples/translator-app/frontend/src/main/resources/logging.properties +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2017, 2023 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. -# - - -#All attributes details -handlers=io.helidon.logging.jul.HelidonConsoleHandler -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 - -#All log level details -.level=INFO - -io.helidon.webserver.level=FINEST -org.glassfish.jersey.internal.Errors.level=SEVERE diff --git a/examples/translator-app/frontend/src/test/java/io/helidon/examples/translator/TranslatorTest.java b/examples/translator-app/frontend/src/test/java/io/helidon/examples/translator/TranslatorTest.java deleted file mode 100644 index 18783ac9cfa..00000000000 --- a/examples/translator-app/frontend/src/test/java/io/helidon/examples/translator/TranslatorTest.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.translator; - -import io.helidon.examples.translator.backend.TranslatorBackendService; -import io.helidon.examples.translator.frontend.TranslatorFrontendService; -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.WebServerConfig; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * The TranslatorTest. - */ -@SuppressWarnings("SpellCheckingInspection") -@ServerTest -public class TranslatorTest { - - private final Http1Client client; - - public TranslatorTest(Http1Client client) { - this.client = client; - } - - @SetUpServer - public static void setUp(WebServerConfig.Builder builder) { - builder.routing(routing -> routing. - register(new TranslatorFrontendService("localhost", 9080))) - .putSocket("backend", socket -> socket - .port(9080) - .routing(routing -> routing.register(new TranslatorBackendService()))); - } - - @Test - public void testCzech() { - try (Http1ClientResponse response = client.get() - .queryParam("q", "cloud") - .queryParam("lang", "czech") - .request()) { - - assertThat("Unexpected response! Status code: " + response.status(), - response.entity().as(String.class), is("oblak\n")); - } - } - - @Test - public void testItalian() { - try (Http1ClientResponse response = client.get() - .queryParam("q", "cloud") - .queryParam("lang", "italian") - .request()) { - - assertThat("Unexpected response! Status code: " + response.status(), - response.entity().as(String.class), is("nube\n")); - } - } - - @Test - public void testFrench() { - try (Http1ClientResponse response = client.get() - .queryParam("q", "cloud") - .queryParam("lang", "french") - .request()) { - - assertThat("Unexpected response! Status code: " + response.status(), - response.entity().as(String.class), is("nuage\n")); - } - } -} diff --git a/examples/translator-app/pom.xml b/examples/translator-app/pom.xml deleted file mode 100644 index 7e72d9efb94..00000000000 --- a/examples/translator-app/pom.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples - helidon-examples-project - 4.1.0-SNAPSHOT - - io.helidon.examples.translator - helidon-examples-translator-project - pom - Helidon Examples Translator Demo - - - A translator example app. - - - - backend - frontend - - diff --git a/examples/webclient/pom.xml b/examples/webclient/pom.xml deleted file mode 100644 index 6010ac27811..00000000000 --- a/examples/webclient/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples - helidon-examples-project - 4.1.0-SNAPSHOT - - - io.helidon.examples.webclient - helidon-examples-webclient-project - Helidon Examples WebClient - - pom - - - standalone - - diff --git a/examples/webclient/standalone/README.md b/examples/webclient/standalone/README.md deleted file mode 100644 index 6557e02d5fa..00000000000 --- a/examples/webclient/standalone/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Standalone WebClient Example - -This example demonstrates how to use the Helidon SE WebClient from a -standalone Java program to connect to a server. - -## Build - -```shell -mvn package -``` - -## Run - -First, start the server: - -```shell -java -jar target/helidon-examples-webclient-standalone.jar -``` - -Note the port number that it displays. For example: - -``` -WEB server is up! http://localhost:PORT/greet -``` - -Then run the client, passing the port number. It will connect -to the server: - -```shell -java -cp "target/classes:target/libs/*" io.helidon.examples.webclient.standalone.ClientMain 35963 -``` - diff --git a/examples/webclient/standalone/pom.xml b/examples/webclient/standalone/pom.xml deleted file mode 100644 index 5fbfa20c22e..00000000000 --- a/examples/webclient/standalone/pom.xml +++ /dev/null @@ -1,101 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - - helidon-examples-webclient-standalone - Helidon Examples WebClient Standalone - - - io.helidon.examples.webclient.standalone.ServerMain - - - - - io.helidon.config - helidon-config-yaml - - - io.helidon.http.media - helidon-http-media-jsonp - - - io.helidon.metrics - helidon-metrics-api - - - io.helidon.metrics.providers - helidon-metrics-providers-micrometer - runtime - - - io.helidon.webclient - helidon-webclient - - - io.helidon.webclient - helidon-webclient-metrics - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver.observe - helidon-webserver-observe - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - - diff --git a/examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/ClientMain.java b/examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/ClientMain.java deleted file mode 100644 index d20343c05f1..00000000000 --- a/examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/ClientMain.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.webclient.standalone; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Map; - -import io.helidon.config.Config; -import io.helidon.config.ConfigValue; -import io.helidon.http.Method; -import io.helidon.http.Status; -import io.helidon.metrics.api.Counter; -import io.helidon.metrics.api.MeterRegistry; -import io.helidon.metrics.api.Metrics; -import io.helidon.webclient.api.HttpClientResponse; -import io.helidon.webclient.api.WebClient; -import io.helidon.webclient.metrics.WebClientMetrics; -import io.helidon.webclient.spi.WebClientService; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; - -/** - * A simple WebClient usage class. - *

        - * Each of the methods demonstrates different usage of the WebClient. - */ -public class ClientMain { - - private static final MeterRegistry METER_REGISTRY = Metrics.globalRegistry(); - private static final JsonBuilderFactory JSON_BUILDER = Json.createBuilderFactory(Map.of()); - private static final JsonObject JSON_NEW_GREETING; - - static { - JSON_NEW_GREETING = JSON_BUILDER.createObjectBuilder() - .add("greeting", "Hola") - .build(); - } - - private ClientMain() { - } - - /** - * Executes WebClient examples. - *

        - * If no argument provided it will take server port from configuration server.port. - *

        - * User can override port from configuration by main method parameter with the specific port. - * - * @param args main method - */ - public static void main(String[] args) { - Config config = Config.create(); - String url; - if (args.length == 0) { - ConfigValue port = config.get("server.port").asInt(); - if (!port.isPresent() || port.get() == -1) { - throw new IllegalStateException("Unknown port! Please specify port as a main method parameter " - + "or directly to config server.port"); - } - url = "http://localhost:" + port.get() + "/greet"; - } else { - url = "http://localhost:" + Integer.parseInt(args[0]) + "/greet"; - } - - WebClient client = WebClient.builder() - .baseUri(url) - .config(config.get("client")) - .build(); - - performPutMethod(client); - performGetMethod(client); - followRedirects(client); - getResponseAsAnJsonObject(client); - saveResponseToFile(client); - clientMetricsExample(url, config); - } - - static Status performPutMethod(WebClient client) { - System.out.println("Put request execution."); - try (HttpClientResponse response = client.put("/greeting").submit(JSON_NEW_GREETING)) { - System.out.println("PUT request executed with status: " + response.status()); - return response.status(); - } - } - - static String performGetMethod(WebClient client) { - System.out.println("Get request execution."); - String result = client.get().requestEntity(String.class); - System.out.println("GET request successfully executed."); - System.out.println(result); - return result; - } - - static String followRedirects(WebClient client) { - System.out.println("Following request redirection."); - try (HttpClientResponse response = client.get("/redirect").request()) { - if (response.status() != Status.OK_200) { - throw new IllegalStateException("Follow redirection failed!"); - } - String result = response.as(String.class); - System.out.println("Redirected request successfully followed."); - System.out.println(result); - return result; - } - } - - static void getResponseAsAnJsonObject(WebClient client) { - System.out.println("Requesting from JsonObject."); - JsonObject jsonObject = client.get().requestEntity(JsonObject.class); - System.out.println("JsonObject successfully obtained."); - System.out.println(jsonObject); - } - - static void saveResponseToFile(WebClient client) { - Path file = Paths.get("test.txt"); - try { - Files.deleteIfExists(file); - } catch (IOException e) { - e.printStackTrace(); - } - - System.out.println("Downloading server response to file: " + file); - try (HttpClientResponse response = client.get().request()) { - Files.copy(response.entity().inputStream(), file); - System.out.println("Download complete!"); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - static String clientMetricsExample(String url, Config config) { - //This part here is only for verification purposes, it is not needed to be done for actual usage. - String counterName = "example.metric.GET.localhost"; - Counter counter = METER_REGISTRY.getOrCreate(Counter.builder(counterName)); - System.out.println(counterName + ": " + counter.count()); - - //Creates new metric which will count all GET requests and has format of example.metric.GET. - WebClientService clientService = WebClientMetrics.counter() - .methods(Method.GET) - .nameFormat("example.metric.%1$s.%2$s") - .build(); - - //This newly created metric now needs to be registered to WebClient. - WebClient client = WebClient.builder() - .baseUri(url) - .config(config) - .addService(clientService) - .build(); - - //Perform any GET request using this newly created WebClient instance. - String result = performGetMethod(client); - //Verification for example purposes that metric has been incremented. - System.out.println(counterName + ": " + counter.count()); - return result; - } -} diff --git a/examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/GreetService.java b/examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/GreetService.java deleted file mode 100644 index e9e777befe2..00000000000 --- a/examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/GreetService.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.webclient.standalone; - -import java.util.Collections; -import java.util.concurrent.atomic.AtomicReference; - -import io.helidon.config.Config; -import io.helidon.http.HeaderNames; -import io.helidon.http.Status; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; - -/** - * 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 HttpService { - - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - /** - * The config value for the key {@code greeting}. - */ - private final AtomicReference greeting = new AtomicReference<>(); - - GreetService() { - Config config = Config.global(); - 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 routing(HttpRules rules) { - rules.get("/", this::getDefaultMessageHandler) - .get("/redirect", this::redirect) - .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 status code of {@link io.helidon.http.Status#MOVED_PERMANENTLY_301} and the new location where should - * client redirect. - * - * @param request the server request - * @param response the server response - */ - private void redirect(ServerRequest request, - ServerResponse response) { - int port = request.context().get(WebServer.class).orElseThrow().port(); - response.headers().add(HeaderNames.LOCATION, "http://localhost:" + port + "/greet/"); - response.status(Status.MOVED_PERMANENTLY_301).send(); - } - - /** - * 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().pathParameters().get("name"); - sendResponse(response, name); - } - - /** - * 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) { - JsonObject jsonObject = request.content().as(JsonObject.class); - updateGreetingFromJson(jsonObject, response); - } - - 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 void updateGreetingFromJson(JsonObject jo, ServerResponse response) { - - if (!jo.containsKey("greeting")) { - JsonObject jsonErrorObject = JSON.createObjectBuilder() - .add("error", "No greeting provided") - .build(); - response.status(Status.BAD_REQUEST_400) - .send(jsonErrorObject); - return; - } - - greeting.set(jo.getString("greeting")); - response.status(Status.NO_CONTENT_204).send(); - } -} diff --git a/examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/ServerMain.java b/examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/ServerMain.java deleted file mode 100644 index e3e9d45add4..00000000000 --- a/examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/ServerMain.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.webclient.standalone; - -import io.helidon.config.Config; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.http.HttpRouting; - -/** - * The application main class. - */ -public final class ServerMain { - - /** - * Cannot be instantiated. - */ - private ServerMain() { - } - - /** - * WebServer starting method. - * - * @param args starting arguments - */ - public static void main(String[] args) { - // By default, this will pick up application.yaml from the classpath - Config config = Config.create(); - Config.global(config); - - WebServerConfig.Builder builder = WebServer.builder(); - setup(builder); - WebServer server = builder.build().start(); - server.context().register(server); - System.out.println("WEB server is up! http://localhost:" + server.port() + "/greet"); - } - - /** - * Set up the server. - * - * @param server server builder - */ - static void setup(WebServerConfig.Builder server) { - Config config = Config.global(); - server.config(config.get("server")) - .routing(ServerMain::routing); - } - - /** - * Setup routing. - * - * @param routing routing builder - */ - private static void routing(HttpRouting.Builder routing) { - routing.register("/greet", new GreetService()); - } -} diff --git a/examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/package-info.java b/examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/package-info.java deleted file mode 100644 index 9cfd5eb785b..00000000000 --- a/examples/webclient/standalone/src/main/java/io/helidon/examples/webclient/standalone/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2020 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. - */ -/** - * Basic examples of webclient usage. - */ -package io.helidon.examples.webclient.standalone; diff --git a/examples/webclient/standalone/src/main/resources/application.yaml b/examples/webclient/standalone/src/main/resources/application.yaml deleted file mode 100644 index 657b26fe54d..00000000000 --- a/examples/webclient/standalone/src/main/resources/application.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2020 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. -# - -app: - greeting: "Hello" - -server: - port: -1 - host: 0.0.0.0 - -client: - follow-redirects: true - max-redirects: 8 \ No newline at end of file diff --git a/examples/webclient/standalone/src/main/resources/full-webclient-config.yaml b/examples/webclient/standalone/src/main/resources/full-webclient-config.yaml deleted file mode 100644 index e106ffd7504..00000000000 --- a/examples/webclient/standalone/src/main/resources/full-webclient-config.yaml +++ /dev/null @@ -1,75 +0,0 @@ -# -# Copyright (c) 2020, 2024 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. -# -client: - event-loop: - name-prefix: client-thread- - workers: 1 - connect-timeout-millis: 2000 - read-timeout-millis: 2000 - follow-redirects: true - max-redirects: 5 - user-agent: "Helidon" - cookies: - automatic-store-enabled: true - default-cookies: - - name: "env" - value: "dev" - headers: - - name: "Accept" - value: ["application/json","text/plain"] - services: - exclude: ["some.webclient.service.Provider"] - config: - metrics: - - type: METER - name-format: "client.meter.overall" - - type: TIMER - # meter per method - name-format: "client.meter.%1$s" - - methods: ["GET"] - type: COUNTER - errors: false - name-format: "client.counter.%1$s.success" - description: "Counter of successful GET requests" - - methods: ["PUT", "POST", "DELETE"] - type: COUNTER - success: false - name-format: "wc.counter.%1$s.error" - description: "Counter of failed PUT, POST and DELETE requests" - - methods: ["GET"] - type: GAUGE_IN_PROGRESS - name-format: "client.inprogress.%2$s" - description: "In progress requests to host" - tracing: - proxy: - use-system-selector: false - host: "hostName" - port: 80 - no-proxy: ["localhost:8080", ".helidon.io", "192.168.1.1"] - ssl: - server: - disable-hostname-verification: false - trust-all: false - truststore: - keystore-resource-path: "path to the keystore" - keystore-type: "JKS" - keystore-passphrase: "changeit" - trust-store: true - client: - keystore: - keystore-resource-path: "path to client keystore" - keystore-passphrase: "changeit" - trust-store: true diff --git a/examples/webclient/standalone/src/test/java/io/helidon/examples/webclient/standalone/ClientMainTest.java b/examples/webclient/standalone/src/test/java/io/helidon/examples/webclient/standalone/ClientMainTest.java deleted file mode 100644 index cd3bc35d944..00000000000 --- a/examples/webclient/standalone/src/test/java/io/helidon/examples/webclient/standalone/ClientMainTest.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.webclient.standalone; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.stream.Stream; - -import io.helidon.config.Config; -import io.helidon.metrics.api.Counter; -import io.helidon.metrics.api.MeterRegistry; -import io.helidon.metrics.api.Metrics; -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; -import io.helidon.webclient.api.WebClient; -import io.helidon.webclient.spi.WebClientService; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - -/** - * Test for verification of WebClient example. - */ -@ServerTest -@TestMethodOrder(MethodOrderer.OrderAnnotation.class) -public class ClientMainTest { - - private static final MeterRegistry METRIC_REGISTRY = Metrics.globalRegistry(); - - private final WebServer server; - private final Path testFile; - - public ClientMainTest(WebServer server) { - this.server = server; - server.context().register(server); - this.testFile = Paths.get("test.txt"); - } - - @SetUpServer - public static void setup(WebServerConfig.Builder server) { - Config.global(Config.create()); - ServerMain.setup(server); - } - - @AfterEach - public void afterEach() throws IOException { - Files.deleteIfExists(testFile); - } - - private WebClient client(WebClientService... services) { - Config config = Config.create(); - return WebClient.builder() - .baseUri("http://localhost:" + server.port() + "/greet") - .config(config.get("client")) - .update(it -> Stream.of(services).forEach(it::addService)) - .build(); - } - - @Test - @Order(1) - public void testPerformRedirect() { - WebClient client = client(); - String greeting = ClientMain.followRedirects(client); - assertThat(greeting, is("{\"message\":\"Hello World!\"}")); - } - - @Test - @Order(2) - public void testFileDownload() throws IOException { - WebClient client = client(); - ClientMain.saveResponseToFile(client); - assertThat(Files.exists(testFile), is(true)); - assertThat(Files.readString(testFile), is("{\"message\":\"Hello World!\"}")); - } - - @Test - @Order(3) - public void testMetricsExample() { - String counterName = "example.metric.GET.localhost"; - Counter counter = METRIC_REGISTRY.getOrCreate(Counter.builder(counterName)); - assertThat("Counter " + counterName + " has not been 0", counter.count(), is(0L)); - ClientMain.clientMetricsExample("http://localhost:" + server.port() + "/greet", Config.create()); - assertThat("Counter " + counterName + " " + "has not been 1", counter.count(), is(1L)); - } - - @Test - @Order(4) - public void testPerformPutAndGetMethod() { - WebClient client = client(); - String greeting = ClientMain.performGetMethod(client); - assertThat(greeting, is("{\"message\":\"Hello World!\"}")); - ClientMain.performPutMethod(client); - greeting = ClientMain.performGetMethod(client); - assertThat(greeting, is("{\"message\":\"Hola World!\"}")); - } - -} diff --git a/examples/webserver/README.md b/examples/webserver/README.md deleted file mode 100644 index 41c29e619fe..00000000000 --- a/examples/webserver/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Helidon SE WebServer Examples - -This directory contains Helidon SE webserver examples. \ No newline at end of file diff --git a/examples/webserver/basic/pom.xml b/examples/webserver/basic/pom.xml deleted file mode 100644 index a675ddb24a8..00000000000 --- a/examples/webserver/basic/pom.xml +++ /dev/null @@ -1,83 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - - io.helidon.examples.webserver - helidon-examples-webserver-basic - Helidon Examples WebServer Basic - - - io.helidon.examples.webserver.basic.BasicMain - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.apache.maven.plugins - maven-failsafe-plugin - - - - integration-test - verify - - - - - - - diff --git a/examples/webserver/basic/src/main/java/io/helidon/examples/webserver/basic/BasicMain.java b/examples/webserver/basic/src/main/java/io/helidon/examples/webserver/basic/BasicMain.java deleted file mode 100644 index f74d2eb6f7c..00000000000 --- a/examples/webserver/basic/src/main/java/io/helidon/examples/webserver/basic/BasicMain.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.webserver.basic; - -import io.helidon.webserver.WebServer; -import io.helidon.webserver.http.HttpRouting; - -/** - * As simple as possible with a fixed port. - */ -public class BasicMain { - private BasicMain() { - } - - /** - * Main method. - * - * @param args ignored - */ - public static void main(String[] args) { - /* - This would be the simplest possible server - We do not use it, as we want testability - */ - /* - WebServer.builder() - .port(8080) - .routing(router -> router.get("/*", (req, res) -> res.send("WebServer Works!"))) - .start(); - */ - WebServer.builder() - .port(8080) - .routing(BasicMain::routing) - .build() - .start(); - } - - /** - * Set up HTTP routing. - * This method is used from both unit and integration tests. - * - * @param router HTTP routing builder to configure routes for this service - */ - static void routing(HttpRouting.Builder router) { - router.get("/*", (req, res) -> res.send("WebServer Works!")); - } -} diff --git a/examples/webserver/basic/src/main/java/io/helidon/examples/webserver/basic/package-info.java b/examples/webserver/basic/src/main/java/io/helidon/examples/webserver/basic/package-info.java deleted file mode 100644 index 1edd0ca72f3..00000000000 --- a/examples/webserver/basic/src/main/java/io/helidon/examples/webserver/basic/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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. - */ - -/** - * Basic example. - */ -package io.helidon.examples.webserver.basic; diff --git a/examples/webserver/basic/src/main/resources/logging.properties b/examples/webserver/basic/src/main/resources/logging.properties deleted file mode 100644 index d09df1098a3..00000000000 --- a/examples/webserver/basic/src/main/resources/logging.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2022, 2023 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. -# -handlers=java.util.logging.ConsoleHandler -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS.%1$tL %5$s%6$s%n -# Global logging level. Can be overridden by specific loggers -.level=INFO -io.helidon.webserver.level=INFO diff --git a/examples/webserver/basic/src/test/java/io/helidon/examples/webserver/basic/AbstractBasicRoutingTest.java b/examples/webserver/basic/src/test/java/io/helidon/examples/webserver/basic/AbstractBasicRoutingTest.java deleted file mode 100644 index d3900c59719..00000000000 --- a/examples/webserver/basic/src/test/java/io/helidon/examples/webserver/basic/AbstractBasicRoutingTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.webserver.basic; - -import io.helidon.webserver.testing.junit5.SetUpRoute; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webserver.http.HttpRouting; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -abstract class AbstractBasicRoutingTest { - private final Http1Client client; - - AbstractBasicRoutingTest(Http1Client client) { - this.client = client; - } - - @SetUpRoute - static void routing(HttpRouting.Builder builder) { - BasicMain.routing(builder); - } - - @Test - void testRootRoute() { - String response = client.get("/") - .request() - .as(String.class); - - assertThat(response, is("WebServer Works!")); - } - - @Test - void testOtherRoute() { - String response = client.get("/longer/path") - .request() - .as(String.class); - - assertThat(response, is("WebServer Works!")); - } -} diff --git a/examples/webserver/basic/src/test/java/io/helidon/examples/webserver/basic/BasicRoutingIT.java b/examples/webserver/basic/src/test/java/io/helidon/examples/webserver/basic/BasicRoutingIT.java deleted file mode 100644 index 3fdb32e1bc1..00000000000 --- a/examples/webserver/basic/src/test/java/io/helidon/examples/webserver/basic/BasicRoutingIT.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.webserver.basic; - -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webclient.http1.Http1Client; - -/** - * An integration test that starts the server and invokes the routing through HTTP. - */ -@ServerTest -class BasicRoutingIT extends AbstractBasicRoutingTest { - BasicRoutingIT(Http1Client client) { - super(client); - } -} diff --git a/examples/webserver/basic/src/test/java/io/helidon/examples/webserver/basic/BasicRoutingTest.java b/examples/webserver/basic/src/test/java/io/helidon/examples/webserver/basic/BasicRoutingTest.java deleted file mode 100644 index fd898ef8603..00000000000 --- a/examples/webserver/basic/src/test/java/io/helidon/examples/webserver/basic/BasicRoutingTest.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.webserver.basic; - -import io.helidon.webserver.testing.junit5.DirectClient; -import io.helidon.webserver.testing.junit5.RoutingTest; - -/** - * A unit test that does not start the server and invokes the routing directly, with no network traffic. - */ -@RoutingTest -class BasicRoutingTest extends AbstractBasicRoutingTest { - BasicRoutingTest(DirectClient client) { - super(client); - } -} diff --git a/examples/webserver/basic/src/test/resources/logging-test.properties b/examples/webserver/basic/src/test/resources/logging-test.properties deleted file mode 100644 index e0e9004a51a..00000000000 --- a/examples/webserver/basic/src/test/resources/logging-test.properties +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) 2022, 2023 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. -# -handlers=java.util.logging.ConsoleHandler -java.util.logging.ConsoleHandler.level=FINEST -java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter -# java.util.logging.SimpleFormatter.format = [%1$tc] %5$s %6$s%n -java.util.logging.SimpleFormatter.format=%1$tH:%1$tM:%1$tS %5$s%6$s%n -# Global logging level. Can be overridden by specific loggers -.level=WARNING diff --git a/examples/webserver/basics/README.md b/examples/webserver/basics/README.md deleted file mode 100644 index c146d43f7ff..00000000000 --- a/examples/webserver/basics/README.md +++ /dev/null @@ -1,45 +0,0 @@ - -# Helidon WebServer Basic Example - -This example consists of various methods that can be selected -at runtime. Each method illustrates a different WebServer concept. -See the comments in `Main.java` for a description of the various -methods. - -## Build and run - -```shell -mvn package -``` - -To see the list of methods that are available run: - -```shell -java -DexampleName=help -jar target/helidon-examples-webserver-basics.jar -``` - -You should see output like: - -``` -Example method names: - help - h - firstRouting - startServer - routingAsFilter - parametersAndHeaders - advancedRouting - organiseCode - readContentEntity - filterAndProcessEntity - supports - errorHandling -``` - -You can then choose the method to execute by setting the `exampleName` system property: - -``` -java -DexampleName=firstRouting -jar target/helidon-examples-webserver-basics.jar -``` - -This will start the Helidon SE WebServer using the method indicated. diff --git a/examples/webserver/basics/pom.xml b/examples/webserver/basics/pom.xml deleted file mode 100644 index 522a16be322..00000000000 --- a/examples/webserver/basics/pom.xml +++ /dev/null @@ -1,85 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.webserver - helidon-examples-webserver-basics - Helidon Examples WebServer Basics - - - Examples of elementary use of the Web Server - - - - io.helidon.examples.webserver.basics.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver - helidon-webserver-static-content - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - io.helidon.http.media - helidon-http-media-jsonp - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/webserver/basics/src/main/java/io/helidon/examples/webserver/basics/Catalog.java b/examples/webserver/basics/src/main/java/io/helidon/examples/webserver/basics/Catalog.java deleted file mode 100644 index c5e7e6bb8e0..00000000000 --- a/examples/webserver/basics/src/main/java/io/helidon/examples/webserver/basics/Catalog.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.webserver.basics; - -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -/** - * Skeleton example of catalog resource use in {@link Main} class. - */ -public class Catalog implements HttpService { - - @Override - public void routing(HttpRules rules) { - rules.get("/", this::list) - .get("/{id}", (req, res) -> getSingle(res, req.path().pathParameters().get("id"))); - } - - private void list(ServerRequest request, ServerResponse response) { - response.send("1, 2, 3, 4, 5"); - } - - private void getSingle(ServerResponse response, String id) { - response.send("Item: " + id); - } -} diff --git a/examples/webserver/basics/src/main/java/io/helidon/examples/webserver/basics/Main.java b/examples/webserver/basics/src/main/java/io/helidon/examples/webserver/basics/Main.java deleted file mode 100644 index 48a3fac6478..00000000000 --- a/examples/webserver/basics/src/main/java/io/helidon/examples/webserver/basics/Main.java +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.webserver.basics; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.lang.reflect.Parameter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import io.helidon.common.media.type.MediaTypes; -import io.helidon.http.HeaderName; -import io.helidon.http.HeaderNames; -import io.helidon.http.HttpException; -import io.helidon.http.ServerRequestHeaders; -import io.helidon.http.Status; -import io.helidon.http.media.EntityReader; -import io.helidon.http.media.MediaContext; -import io.helidon.http.media.MediaContextConfig; -import io.helidon.http.media.ReadableEntity; -import io.helidon.http.media.jsonp.JsonpSupport; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.http.ErrorHandler; -import io.helidon.webserver.http.Handler; -import io.helidon.webserver.http.HttpRouting; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; -import io.helidon.webserver.staticcontent.StaticContentService; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; - -/** - * This example consists of few first tutorial steps of WebServer API. Each step is represented by a single method. - *

        - * Principles: - *

          - *
        • Reactive principles
        • - *
        • Reflection free
        • - *
        • Fluent
        • - *
        • Integration platform
        • - *
        - *

        - * It is also java executable main class. Use a method name as a command line parameter to execute. - */ -public class Main { - - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - private static final HeaderName BAR_HEADER = HeaderNames.create("bar"); - private static final HeaderName FOO_HEADER = HeaderNames.create("foo"); - - // ---------------- EXAMPLES - - /** - * True heart of WebServer API is {@link HttpRouting}. - * It provides fluent way how to assign custom {@link Handler} to the routing rule. - * The rule consists from two main factors - HTTP method and path pattern. - *

        - * The (route) {@link Handler} is a functional interface which process HTTP {@link ServerRequest request} and - * writes to the {@link ServerResponse response}. - * - * @param routing routing builder - */ - public static void firstRouting(HttpRouting.Builder routing) { - routing.post("/firstRouting/post-endpoint", (req, res) -> res.status(Status.CREATED_201) - .send()) - .get("/firstRouting/get-endpoint", (req, res) -> res.status(Status.OK_200) - .send("Hello World!")); - } - - /** - * All routing rules (routes) are evaluated in a definition order. The {@link Handler} assigned with the first valid route - * for given request is called. It is a responsibility of each handler to process in one of the following ways: - *

          - *
        • Respond using one of {@link ServerResponse#send() ServerResponse.send(...)} method.
        • - *
        • Continue to next valid route using {@link ServerResponse#next() ServerRequest.next()} method. - * It is possible to define filtering handlers.
        • - *
        - *

        - * If no valid {@link Handler} is found then routing respond by {@code HTTP 404} code. - *

        - * If selected {@link Handler} doesn't process request than the request stacks! - *

        - * Blocking operations:
        - * For performance reason, {@link Handler} can be called directly by a selector thread. It is not good idea to block - * such thread. If request must be processed by a blocking operation then such processing should be deferred to another - * thread. - * - * @param routing routing builder - */ - public static void routingAsFilter(HttpRouting.Builder routing) { - routing.any("/routingAsFilter/*", (req, res) -> { - System.out.println(req.prologue().method() + " " + req.path()); - // Filters are just routing handlers which calls next() - res.next(); - }) - .post("/routingAsFilter/post-endpoint", (req, res) -> res.status(Status.CREATED_201) - .send()) - .get("/routingAsFilter/get-endpoint", (req, res) -> res.status(Status.OK_200) - .send("Hello World!")); - } - - /** - * {@link ServerRequest} provides access to three types of "parameters": - *

          - *
        • Headers
        • - *
        • Query parameters
        • - *
        • Path parameters - Evaluated from provided {@code path pattern}
        • - *
        - *

        - * {@link java.util.Optional Optional} API is heavily used to represent parameters optionality. - *

        - * WebServer {@link io.helidon.common.parameters.Parameters Parameters} API is used to represent fact, that headers and - * query parameters can contain multiple values. - * - * @param routing routing builder - */ - public static void parametersAndHeaders(HttpRouting.Builder routing) { - routing.get("/parametersAndHeaders/context/{id}", (req, res) -> { - StringBuilder sb = new StringBuilder(); - // Request headers - req.headers() - .first(FOO_HEADER) - .ifPresent(v -> sb.append("foo: ").append(v).append("\n")); - // Request parameters - req.query() - .first("bar") - .ifPresent(v -> sb.append("bar: ").append(v).append("\n")); - // Path parameters - sb.append("id: ").append(req.path().pathParameters().get("id")); - // Response headers - res.headers().contentType(MediaTypes.TEXT_PLAIN); - // Response entity (payload) - res.send(sb.toString()); - }); - } - - /** - * Routing rules (routes) are limited on two criteria - HTTP method and path. - * - * @param routing routing builder - */ - public static void advancedRouting(HttpRouting.Builder routing) { - routing.get("/advancedRouting/foo", (req, res) -> { - ServerRequestHeaders headers = req.headers(); - if (headers.isAccepted(MediaTypes.TEXT_PLAIN) - && headers.contains(BAR_HEADER)) { - - res.send(); - } else { - res.next(); - } - }); - } - - /** - * Larger applications with many routing rules can cause complicated readability (maintainability) if all rules are - * defined in a single fluent code. It is possible to register {@link HttpService} and organise - * the code into services and resources. {@code Service} is an interface which can register more routing rules (routes). - * - * @param routing routing builder - */ - public static void organiseCode(HttpRouting.Builder routing) { - routing.register("/organiseCode/catalog-context-path", new Catalog()); - } - - /** - * Request payload (body/entity) is represented by {@link ReadableEntity}. - * But it is more convenient to process entity in some type specific form. WebServer supports few types which can be - * used te read the whole entity: - *

          - *
        • {@code byte[]}
        • - *
        • {@code String}
        • - *
        • {@code InputStream}
        • - *
        - *

        - * Similar approach is used for the response entity. - * - * @param routing routing builder - */ - public static void readContentEntity(HttpRouting.Builder routing) { - routing.post("/readContentEntity/foo", (req, res) -> { - try { - String data = req.content().as(String.class); - System.out.println("/foo DATA: " + data); - res.send(data); - } catch (Throwable th) { - res.status(Status.BAD_REQUEST_400); - } - }) - // It is possible to use Handler.of() method to automatically cover all error states. - .post("/readContentEntity/bar", Handler.create(String.class, (data, res) -> { - System.out.println("/foo DATA: " + data); - res.send(data); - })); - } - - /** - * Use a custom {@link EntityReader reader} to convert the request content into an object of a given type. - * - * @param routing routing builder - * @param mediaContext media context builder - */ - public static void mediaReader(HttpRouting.Builder routing, MediaContextConfig.Builder mediaContext) { - routing.post("/mediaReader/create-record", Handler.create(Name.class, (name, res) -> { - System.out.println("Name: " + name); - res.status(Status.CREATED_201) - .send(name.toString()); - })); - - // add our custom Name reader - mediaContext.addMediaSupport(NameSupport.create()); - } - - /** - * Combination of filtering {@link Handler} pattern with {@link HttpService} registration capabilities - * can be used by other frameworks for the integration. WebServer is shipped with several integrated libraries (supports) - * including static content, JSON and Jersey. See {@code POM.xml} for requested dependencies. - * - * @param routing routing builder - * @param mediaContext mediaContext - */ - public static void supports(HttpRouting.Builder routing, MediaContextConfig.Builder mediaContext) { - routing.register("/supports", StaticContentService.create("/static")) - .get("/supports/hello/{what}", (req, res) -> - res.send(JSON.createObjectBuilder() - .add("message", "Hello " + req.path() - .pathParameters() - .get("what")) - .build())); - mediaContext.addMediaSupport(JsonpSupport.create()); - } - - /** - * Request processing can cause error represented by {@link Throwable}. It is possible to register custom - * {@link ErrorHandler ErrorHandlers} for specific processing. - *

        - * If error is not processed by a custom {@link ErrorHandler ErrorHandler} than default one is used. - * It responds with HTTP 500 code unless error is not represented - * by {@link HttpException HttpException}. In such case it reflects its content. - * - * @param routing routing builder - */ - public static void errorHandling(HttpRouting.Builder routing) { - routing.post("/errorHandling/compute", Handler.create(String.class, (str, res) -> { - int result = 100 / Integer.parseInt(str); - res.send("100 / " + str + " = " + result); - })) - .error(Throwable.class, (req, res, ex) -> { - ex.printStackTrace(System.out); - res.next(); - }) - .error(NumberFormatException.class, - (req, res, ex) -> res.status(Status.BAD_REQUEST_400).send()) - .error(ArithmeticException.class, - (req, res, ex) -> res.status(Status.PRECONDITION_FAILED_412).send()); - } - - - // ---------------- EXECUTION - - private static final String EXAMPLE_NAME_SYS_PROP = "exampleName"; - private static final String EXAMPLE_NAME_ENV_VAR = "EXAMPLE_NAME"; - - /** - * Prints usage instructions. - */ - public void help() { - StringBuilder hlp = new StringBuilder(); - hlp.append("java -jar example-basics.jar \n"); - hlp.append("Example method names:\n"); - Method[] methods = Main.class.getDeclaredMethods(); - for (Method method : methods) { - if (Modifier.isPublic(method.getModifiers()) && !Modifier.isStatic(method.getModifiers())) { - hlp.append(" ").append(method.getName()).append('\n'); - } - } - hlp.append('\n'); - hlp.append("Example method name can be also provided as a\n"); - hlp.append(" - -D").append(EXAMPLE_NAME_SYS_PROP).append(" jvm property.\n"); - hlp.append(" - ").append(EXAMPLE_NAME_ENV_VAR).append(" environment variable.\n"); - System.out.println(hlp); - } - - /** - * Prints usage instructions. (Shortcut to {@link #help()} method. - */ - public void h() { - help(); - } - - /** - * Java main method. - * - * @param args Command line arguments. - */ - public static void main(String[] args) { - String exampleName; - if (args.length > 0) { - exampleName = args[0]; - } else if (System.getProperty(EXAMPLE_NAME_SYS_PROP) != null) { - exampleName = System.getProperty(EXAMPLE_NAME_SYS_PROP); - } else if (System.getenv(EXAMPLE_NAME_ENV_VAR) != null) { - exampleName = System.getenv(EXAMPLE_NAME_ENV_VAR); - } else { - System.out.println("Missing example name. It can be provided as a \n" - + " - first command line argument.\n" - + " - -D" + EXAMPLE_NAME_SYS_PROP + " jvm property.\n" - + " - " + EXAMPLE_NAME_ENV_VAR + " environment variable.\n"); - System.exit(1); - return; - } - while (exampleName.startsWith("-")) { - exampleName = exampleName.substring(1); - } - String methodName = exampleName; - Method method = Arrays.stream(Main.class.getMethods()) - .filter(m -> m.getName().equals(methodName)) - .findFirst() - .orElseThrow(() -> new IllegalArgumentException("Missing example method named: " + methodName)); - HttpRouting.Builder routingBuilder = HttpRouting.builder(); - MediaContextConfig.Builder mediaContextBuilder = MediaContext.builder() - .mediaSupportsDiscoverServices(false); - List params = new ArrayList<>(); - for (Parameter param : method.getParameters()) { - Class paramType = param.getType(); - if (paramType.isAssignableFrom(routingBuilder.getClass())) { - params.add(routingBuilder); - } else if (paramType.isAssignableFrom(mediaContextBuilder.getClass())) { - params.add(mediaContextBuilder); - } else { - throw new IllegalStateException("Unsupported parameter type: " + paramType.getName()); - } - } - WebServer server; - try { - method.invoke(null, params.toArray(new Object[0])); - } catch (IllegalArgumentException e) { - System.out.println(e.getMessage()); - System.exit(2); - } catch (IllegalAccessException | InvocationTargetException e) { - e.printStackTrace(System.out); - System.exit(100); - } - server = WebServer.builder() - .routing(routingBuilder) - .mediaContext(mediaContextBuilder.build()) - .build() - .start(); - System.out.println("Server is UP: http://localhost:" + server.port()); - } -} diff --git a/examples/webserver/basics/src/main/java/io/helidon/examples/webserver/basics/Name.java b/examples/webserver/basics/src/main/java/io/helidon/examples/webserver/basics/Name.java deleted file mode 100644 index 8d1c581db30..00000000000 --- a/examples/webserver/basics/src/main/java/io/helidon/examples/webserver/basics/Name.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.webserver.basics; - -/** - * Represents a simple entity - the name. - */ -public class Name { - - private final String firstName; - private final String middleName; - private final String lastName; - - /** - * An naive implementation of name parser. - * - * @param fullName a full name - */ - public Name(String fullName) { - String[] split = fullName.split(" "); - switch (split.length) { - case 0: - throw new IllegalArgumentException("An empty name"); - case 1: - firstName = null; - middleName = null; - lastName = split[0]; - break; - case 2: - firstName = split[0]; - middleName = null; - lastName = split[1]; - break; - case 3: - firstName = split[0]; - middleName = split[1]; - lastName = split[2]; - break; - default: - throw new IllegalArgumentException("To many name parts!"); - } - } - - public String getFirstName() { - return firstName; - } - - public String getMiddleName() { - return middleName; - } - - public String getLastName() { - return lastName; - } - - @Override - public String toString() { - StringBuilder result = new StringBuilder(); - if (firstName != null) { - result.append(firstName); - } - if (middleName != null) { - if (result.length() > 0) { - result.append(' '); - } - result.append(middleName); - } - if (lastName != null) { - if (result.length() > 0) { - result.append(' '); - } - result.append(lastName); - } - return result.toString(); - } -} diff --git a/examples/webserver/basics/src/main/java/io/helidon/examples/webserver/basics/NameSupport.java b/examples/webserver/basics/src/main/java/io/helidon/examples/webserver/basics/NameSupport.java deleted file mode 100644 index ffa68b3276c..00000000000 --- a/examples/webserver/basics/src/main/java/io/helidon/examples/webserver/basics/NameSupport.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.webserver.basics; - -import java.io.IOException; -import java.io.InputStream; -import java.io.UncheckedIOException; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; - -import io.helidon.common.GenericType; -import io.helidon.http.Headers; -import io.helidon.http.HttpMediaType; -import io.helidon.http.media.EntityReader; -import io.helidon.http.media.MediaSupport; - -/** - * Reader for the custom media type. - */ -public class NameSupport implements MediaSupport { - - static final HttpMediaType APP_NAME = HttpMediaType.create("application/name"); - - private NameSupport() { - } - - /** - * Create a new instance. - * - * @return new instance - */ - public static NameSupport create() { - return new NameSupport(); - } - - @SuppressWarnings("unchecked") - @Override - public ReaderResponse reader(GenericType type, Headers headers) { - if (!type.rawType().equals(Name.class) - || !headers.contentType().map(APP_NAME::equals).orElse(false)) { - return ReaderResponse.unsupported(); - } - return (ReaderResponse) new ReaderResponse<>(SupportLevel.SUPPORTED, () -> new EntityReader() { - @Override - public Name read(GenericType type, InputStream stream, Headers headers) { - return read(stream, headers); - } - - @Override - public Name read(GenericType type, - InputStream stream, - Headers requestHeaders, - Headers responseHeaders) { - return read(stream, responseHeaders); - } - - private Name read(InputStream stream, Headers headers) { - Charset charset = headers.contentType() - .flatMap(HttpMediaType::charset) - .map(Charset::forName) - .orElse(StandardCharsets.UTF_8); - - try (stream) { - return new Name(new String(stream.readAllBytes(), charset)); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - }); - } - - @Override - public String name() { - return "name"; - } - - @Override - public String type() { - return "name"; - } -} - - - - diff --git a/examples/webserver/basics/src/main/java/io/helidon/examples/webserver/basics/package-info.java b/examples/webserver/basics/src/main/java/io/helidon/examples/webserver/basics/package-info.java deleted file mode 100644 index efce08d4f8f..00000000000 --- a/examples/webserver/basics/src/main/java/io/helidon/examples/webserver/basics/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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. - */ - -/** - * A set of small usage examples. Start with {@link io.helidon.examples.webserver.basics.Main Main} class. - */ -package io.helidon.examples.webserver.basics; diff --git a/examples/webserver/basics/src/main/resources/static/index.html b/examples/webserver/basics/src/main/resources/static/index.html deleted file mode 100644 index 82a701ccfb4..00000000000 --- a/examples/webserver/basics/src/main/resources/static/index.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - Just index - - -

        Example

        - - diff --git a/examples/webserver/basics/src/test/java/io/helidon/examples/webserver/basics/MainTest.java b/examples/webserver/basics/src/test/java/io/helidon/examples/webserver/basics/MainTest.java deleted file mode 100644 index d33ab90160a..00000000000 --- a/examples/webserver/basics/src/test/java/io/helidon/examples/webserver/basics/MainTest.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.webserver.basics; - -import io.helidon.common.media.type.MediaTypes; -import io.helidon.http.HeaderName; -import io.helidon.http.HeaderNames; -import io.helidon.http.media.MediaContext; -import io.helidon.http.media.MediaContextConfig; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; - -import org.junit.jupiter.api.Test; - -import static io.helidon.http.Status.BAD_REQUEST_400; -import static io.helidon.http.Status.CREATED_201; -import static io.helidon.http.Status.INTERNAL_SERVER_ERROR_500; -import static io.helidon.http.Status.OK_200; -import static io.helidon.http.Status.PRECONDITION_FAILED_412; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -@ServerTest -public class MainTest { - - private static final HeaderName FOO_HEADER = HeaderNames.create("foo"); - - private final Http1Client client; - - public MainTest(Http1Client client) { - this.client = client; - } - - @SetUpServer - static void setup(WebServerConfig.Builder server) { - MediaContextConfig.Builder mediaContext = MediaContext.builder() - .mediaSupportsDiscoverServices(false); - server.routing(routing -> { - Main.firstRouting(routing); - Main.mediaReader(routing, mediaContext); - Main.advancedRouting(routing); - Main.organiseCode(routing); - Main.routingAsFilter(routing); - Main.parametersAndHeaders(routing); - Main.errorHandling(routing); - Main.readContentEntity(routing); - Main.supports(routing, mediaContext); - }); - server.mediaContext(mediaContext.build()); - } - - @Test - public void firstRouting() { - // POST - try (Http1ClientResponse response = client.post("/firstRouting/post-endpoint").request()) { - assertThat(response.status(), is(CREATED_201)); - } - // GET - try (Http1ClientResponse response = client.get("/firstRouting/get-endpoint").request()) { - assertThat(response.status(), is(OK_200)); - } - } - - @Test - public void routingAsFilter() { - // POST - try (Http1ClientResponse response = client.post("/routingAsFilter/post-endpoint").request()) { - assertThat(response.status(), is(CREATED_201)); - } - // GET - try (Http1ClientResponse response = client.get("/routingAsFilter/get-endpoint").request()) { - assertThat(response.status(), is(OK_200)); - } - } - - @Test - public void parametersAndHeaders() { - try (Http1ClientResponse response = client.get("/parametersAndHeaders/context/aaa") - .queryParam("bar", "bbb") - .header(FOO_HEADER, "ccc") - .request()) { - - assertThat(response.status(), is(OK_200)); - String s = response.entity().as(String.class); - assertThat(s, containsString("id: aaa")); - assertThat(s, containsString("bar: bbb")); - assertThat(s, containsString("foo: ccc")); - } - } - - @Test - public void organiseCode() { - // List - try (Http1ClientResponse response = client.get("/organiseCode/catalog-context-path").request()) { - assertThat(response.status(), is(OK_200)); - assertThat(response.entity().as(String.class), is("1, 2, 3, 4, 5")); - } - - // Get by id - try (Http1ClientResponse response = client.get("/organiseCode/catalog-context-path/aaa").request()) { - assertThat(response.status(), is(OK_200)); - assertThat(response.entity().as(String.class), is("Item: aaa")); - } - } - - @Test - public void readContentEntity() { - // foo - try (Http1ClientResponse response = client.post("/readContentEntity/foo").submit("aaa")) { - assertThat(response.status(), is(OK_200)); - assertThat(response.entity().as(String.class), is("aaa")); - } - - // bar - try (Http1ClientResponse response = client.post("/readContentEntity/bar").submit("aaa")) { - assertThat(response.status(), is(OK_200)); - assertThat(response.entity().as(String.class), is("aaa")); - } - } - - @Test - public void mediaReader() { - try (Http1ClientResponse response = client.post("/mediaReader/create-record") - .contentType(NameSupport.APP_NAME) - .submit("John Smith")) { - assertThat(response.status(), is(CREATED_201)); - assertThat(response.entity().as(String.class), is("John Smith")); - } - - // Unsupported Content-Type - try (Http1ClientResponse response = client.post("/mediaReader/create-record") - .contentType(MediaTypes.TEXT_PLAIN) - .submit("John Smith")) { - assertThat(response.status(), is(INTERNAL_SERVER_ERROR_500)); - } - } - - @Test - public void supports() { - // Static content - try (Http1ClientResponse response = client.get("/supports/index.html").request()) { - assertThat(response.status(), is(OK_200)); - assertThat(response.headers().first(HeaderNames.CONTENT_TYPE).orElse(null), is(MediaTypes.TEXT_HTML.text())); - } - - // JSON - try (Http1ClientResponse response = client.get("/supports/hello/Europe").request()) { - assertThat(response.status(), is(OK_200)); - assertThat(response.entity().as(String.class), is("{\"message\":\"Hello Europe\"}")); - } - } - - @Test - public void errorHandling() { - // Valid - try (Http1ClientResponse response = client.post("/errorHandling/compute") - .contentType(MediaTypes.TEXT_PLAIN) - .submit("2")) { - assertThat(response.status(), is(OK_200)); - assertThat(response.entity().as(String.class), is("100 / 2 = 50")); - } - - // Zero - try (Http1ClientResponse response = client.post("/errorHandling/compute") - .contentType(MediaTypes.TEXT_PLAIN) - .submit("0")) { - assertThat(response.status(), is(PRECONDITION_FAILED_412)); - } - - // NaN - try (Http1ClientResponse response = client.post("/errorHandling/compute") - .contentType(MediaTypes.TEXT_PLAIN) - .submit("aaa")) { - assertThat(response.status(), is(BAD_REQUEST_400)); - } - } -} diff --git a/examples/webserver/comment-aas/README.md b/examples/webserver/comment-aas/README.md deleted file mode 100644 index 3918c032daf..00000000000 --- a/examples/webserver/comment-aas/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Comments As a Service - -This application allows users to add or read short comments related to a single topic. - Topic can be anything including blog post, newspaper article, and others. - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-webserver-comment-aas.jar -``` - -Try the application: - -```shell -curl http://localhost:8080/comments/java -d "I use Helidon!" -curl http://localhost:8080/comments/java -d "I use vertx" -curl http://localhost:8080/comments/java -d "I use spring" -curl http://localhost:8080/comments/java -``` diff --git a/examples/webserver/comment-aas/etc/add-comment b/examples/webserver/comment-aas/etc/add-comment deleted file mode 100755 index d76f88f21e5..00000000000 --- a/examples/webserver/comment-aas/etc/add-comment +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2017, 2021 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. -# - -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -if [ -f "$SCRIPT_DIR/user.txt" ]; then - export SVC_USER=`cat "$SCRIPT_DIR/user.txt"` -fi - -if [ -z "$2" ]; then - echo "Missing command line parameter! Usage: comment.sh " - exit 1 -fi - -if [ -z "$SVC_USER" ]; then - echo "Contacting service http://localhost:8080" - echo "" - curl --noproxy localhost -X POST --data "$2" http://localhost:8080/comments/$1 -else - echo "Contacting service http://localhost:8080 as $SVC_USER" - echo "" - curl --noproxy localhost -H "user-identity: $SVC_USER" -X POST --data "$2" http://localhost:8080/comments/$1 -fi -echo "" diff --git a/examples/webserver/comment-aas/etc/config.yaml b/examples/webserver/comment-aas/etc/config.yaml deleted file mode 100644 index 2601b6f8c9d..00000000000 --- a/examples/webserver/comment-aas/etc/config.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2017, 2021 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. -# - -anonymous-enabled: false diff --git a/examples/webserver/comment-aas/etc/create-etcd b/examples/webserver/comment-aas/etc/create-etcd deleted file mode 100755 index 6c5f1b1292e..00000000000 --- a/examples/webserver/comment-aas/etc/create-etcd +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2017, 2021 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. -# - -export SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -export ETCD_DATA_DIRS=/tmp/etcd-data/config-gerrit-etcd-data-dirs -rm -rf $ETCD_DATA_DIRS -export CONTAINER_NAME="config-etcd" - -docker rm -f $CONTAINER_NAME -export HOST_IP=`ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1'` - -docker run -d \ - -v $ETCD_DATA_DIRS:/var/data-dir \ - -p 2380:2380 \ - -p 2379:2379 \ - --name $CONTAINER_NAME \ - quay.io/coreos/etcd:v3.1.3 \ - etcd \ - -name etcd \ - -data-dir /var/data-dir \ - -advertise-client-urls http://$HOST_IP:2380 \ - -listen-client-urls http://0.0.0.0:2379 \ - -initial-advertise-peer-urls http://$HOST_IP:2380 \ - -listen-peer-urls http://0.0.0.0:2380 - -echo "Run with name $CONTAINER_NAME" - -echo "Test:" -docker exec $CONTAINER_NAME /bin/sh -c "ETCDCTL_API=3 etcdctl put my-key my-value" diff --git a/examples/webserver/comment-aas/etc/get-etcd-config b/examples/webserver/comment-aas/etc/get-etcd-config deleted file mode 100755 index eca74b3f078..00000000000 --- a/examples/webserver/comment-aas/etc/get-etcd-config +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2017, 2021 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. -# - -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -HOST_IP=`ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1'` - -echo "Retrieving configuration from ETCD:" -curl --noproxy $HOST_IP http://$HOST_IP:2379/v2/keys/comments-aas-config | python -m json.tool diff --git a/examples/webserver/comment-aas/etc/list-comments b/examples/webserver/comment-aas/etc/list-comments deleted file mode 100755 index 18cc0ec5997..00000000000 --- a/examples/webserver/comment-aas/etc/list-comments +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2017, 2021 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. -# - -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -if [ -f "$SCRIPT_DIR/user.txt" ]; then - export SVC_USER=`cat "$SCRIPT_DIR/user.txt"` -fi - -if [ -z "$1" ]; then - echo "Missing command line parameter! Usage: list_comments.sh " - exit 1 -fi - -if [ -z "$SVC_USER" ]; then - echo "Contacting service http://localhost:8080" - echo "" - curl --noproxy localhost http://localhost:8080/comments/$1 -else - echo "Contacting service http://localhost:8080 as $SVC_USER" - echo "" - curl --noproxy localhost -H "user-identity: $SVC_USER" http://localhost:8080/comments/$1 -fi -echo "" diff --git a/examples/webserver/comment-aas/etc/put-etcd-config b/examples/webserver/comment-aas/etc/put-etcd-config deleted file mode 100755 index 0ca9f6b9aa1..00000000000 --- a/examples/webserver/comment-aas/etc/put-etcd-config +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2017, 2021 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. -# - -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -HOST_IP=`ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1'` -CONFIG_FILE="$SCRIPT_DIR/config.yaml" - -if [ -f "$CONFIG_FILE" ]; then - echo "Storing configuration into ETCD: $CONFIG_FILE" - curl --noproxy $HOST_IP -vvv http://$HOST_IP:2379/v2/keys/comments-aas-config -XPUT --data-urlencode value@$CONFIG_FILE -else - echo "Configuration file $CONFIG_FILE not found. DO NOT IMPORT INTO ETCD!" -fi diff --git a/examples/webserver/comment-aas/etc/start-etcd b/examples/webserver/comment-aas/etc/start-etcd deleted file mode 100755 index c3ae59070f6..00000000000 --- a/examples/webserver/comment-aas/etc/start-etcd +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2017, 2021 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. -# - -CONTAINER_NAME="config-etcd" -docker start $CONTAINER_NAME diff --git a/examples/webserver/comment-aas/etc/stop-comment-service b/examples/webserver/comment-aas/etc/stop-comment-service deleted file mode 100755 index 21def952ce1..00000000000 --- a/examples/webserver/comment-aas/etc/stop-comment-service +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2017, 2021 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. -# - -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -if [ -f "$SCRIPT_DIR/user.txt" ]; then - export SVC_USER=`cat "$SCRIPT_DIR/user.txt"` -fi - -if [ -z "$SVC_USER" ]; then - echo "Contacting service http://localhost:8080" - echo "" - curl --noproxy localhost -X POST http://localhost:8080/mgmt/shutdown -else - echo "Contacting service http://localhost:8080 as $SVC_USER" - echo "" - curl --noproxy localhost -H "user-identity: $SVC_USER" -X POST http://localhost:8080/mgmt/shutdown -fi -echo "" diff --git a/examples/webserver/comment-aas/etc/stop-etcd b/examples/webserver/comment-aas/etc/stop-etcd deleted file mode 100755 index e54f1ea70e0..00000000000 --- a/examples/webserver/comment-aas/etc/stop-etcd +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2017, 2021 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. -# - -CONTAINER_NAME="config-etcd" -docker stop $CONTAINER_NAME diff --git a/examples/webserver/comment-aas/etc/switch-user b/examples/webserver/comment-aas/etc/switch-user deleted file mode 100755 index 49740ba3a90..00000000000 --- a/examples/webserver/comment-aas/etc/switch-user +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2017, 2021 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. -# - -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -if [ -z "$1" ]; then - echo "set empty context user!" - rm -f "$SCRIPT_DIR/user.txt" -else - echo "set context user: $1" - echo "$1" > "$SCRIPT_DIR/user.txt" -fi diff --git a/examples/webserver/comment-aas/pom.xml b/examples/webserver/comment-aas/pom.xml deleted file mode 100644 index b5a1c3b2c9a..00000000000 --- a/examples/webserver/comment-aas/pom.xml +++ /dev/null @@ -1,91 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.webserver - helidon-examples-webserver-comment-aas - Helidon Examples WebServer CommentsAAS - - Comments As A Service example application - - - io.helidon.examples.webserver.comments.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.http - helidon-http - - - io.helidon.common - helidon-common - - - io.helidon.config - helidon-config - - - io.helidon.config - helidon-config-yaml - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/webserver/comment-aas/src/main/java/io/helidon/examples/webserver/comments/CommentsService.java b/examples/webserver/comment-aas/src/main/java/io/helidon/examples/webserver/comments/CommentsService.java deleted file mode 100644 index 11c81acecae..00000000000 --- a/examples/webserver/comment-aas/src/main/java/io/helidon/examples/webserver/comments/CommentsService.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.webserver.comments; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; - -import io.helidon.http.HttpMediaTypes; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -/** - * Basic service for comments. - */ -public class CommentsService implements HttpService { - - private final ConcurrentHashMap> topicsAndComments = new ConcurrentHashMap<>(); - - @Override - public void routing(HttpRules rules) { - rules.get("/{topic}", this::handleListComments) - .post("/{topic}", this::handleAddComment); - } - - private void handleListComments(ServerRequest req, ServerResponse resp) { - String topic = req.path().pathParameters().get("topic"); - resp.headers().contentType(HttpMediaTypes.PLAINTEXT_UTF_8); - resp.send(listComments(topic)); - } - - private void handleAddComment(ServerRequest req, ServerResponse res) { - String topic = req.path().pathParameters().get("topic"); - String userName = req.context().get("user", String.class).orElse("anonymous"); - String msg = req.content().as(String.class); - addComment(msg, userName, topic); - res.send(); - } - - /** - * Adds new comment into the comment-room. - * - * @param message a comment message - * @param fromUser a user alias of the comment author - */ - void addComment(String message, String fromUser, String toTopic) { - ProfanityDetector.detectProfanity(message); - if (fromUser == null) { - fromUser = "anonymous"; - } - List comments = - topicsAndComments.computeIfAbsent(toTopic, k -> Collections.synchronizedList(new ArrayList<>())); - comments.add(new Comment(fromUser, message)); - } - - /** - * List all comments in original order as a string with single comment on the line. - * - * @param roomName a name of the room - * @return all comments, line-by-line - */ - String listComments(String roomName) { - List comments = topicsAndComments.get(roomName); - if (comments != null) { - return comments.stream() - .map(String::valueOf) - .collect(Collectors.joining("\n")); - } - return ""; - } - - private record Comment(String userName, String message) { - - @Override - public String toString() { - StringBuilder result = new StringBuilder(); - if (userName != null) { - result.append(userName); - } - result.append(": "); - result.append(message); - return result.toString(); - } - } -} diff --git a/examples/webserver/comment-aas/src/main/java/io/helidon/examples/webserver/comments/Main.java b/examples/webserver/comment-aas/src/main/java/io/helidon/examples/webserver/comments/Main.java deleted file mode 100644 index ce5f90d0509..00000000000 --- a/examples/webserver/comment-aas/src/main/java/io/helidon/examples/webserver/comments/Main.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.webserver.comments; - -import java.util.Optional; - -import io.helidon.config.Config; -import io.helidon.http.HeaderName; -import io.helidon.http.HeaderNames; -import io.helidon.http.HttpException; -import io.helidon.http.Status; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.http.HttpRouting; - -/** - * Application java main class. - *

        - *

        The COMMENTS-As-a-Service application example demonstrates Web Server in its integration role. - * It integrates various components including Configuration and Security. - *

        - *

        This WEB application provides possibility to store and read comment related to various topics. - */ -public final class Main { - - static final HeaderName USER_IDENTITY_HEADER = HeaderNames.create("user-identity"); - - private Main() { - } - - /** - * A java main class. - * - * @param args command line arguments. - */ - public static void main(String[] args) { - WebServerConfig.Builder builder = WebServer.builder(); - setup(builder); - WebServer server = builder.build().start(); - - System.out.println("WEB server is up! http://localhost:" + server.port() + "/comments"); - } - - static void routing(HttpRouting.Builder routing, boolean acceptAnonymousUsers) { - // Filter that translates user identity header into the contextual "user" information - routing.any((req, res) -> { - String user = req.headers() - .first(USER_IDENTITY_HEADER) - .or(() -> acceptAnonymousUsers ? Optional.of("anonymous") : Optional.empty()) - .orElseThrow(() -> new HttpException("Anonymous access is forbidden!", Status.FORBIDDEN_403)); - - req.context().register("user", user); - res.next(); - }) - // Main service logic part is registered as a separated class to "/comments" context root - .register("/comments", new CommentsService()) - // Error handling for argot expressions. - .error(ProfanityException.class, (req, res, ex) -> { - res.status(Status.NOT_ACCEPTABLE_406); - res.send("Expressions like '" + ex.getObfuscatedProfanity() + "' are unacceptable!"); - }) - .error(HttpException.class, (req, res, ex) -> { - if (ex.status() == Status.FORBIDDEN_403) { - res.status(ex.status()); - res.send(ex.getMessage()); - } else { - res.next(); - } - }); - } - - static void setup(WebServerConfig.Builder server) { - // Load configuration - Config config = Config.create(); - - server.config(config) - .routing(r -> routing(r, config.get("anonymous-enabled").asBoolean().orElse(false))); - } -} diff --git a/examples/webserver/comment-aas/src/main/java/io/helidon/examples/webserver/comments/ProfanityDetector.java b/examples/webserver/comment-aas/src/main/java/io/helidon/examples/webserver/comments/ProfanityDetector.java deleted file mode 100644 index 0bab2520459..00000000000 --- a/examples/webserver/comment-aas/src/main/java/io/helidon/examples/webserver/comments/ProfanityDetector.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.webserver.comments; - -/** - * Simple profanity detection utility class. - */ -class ProfanityDetector { - private static final String[] BANNED_TERMS = new String[] {"spring", "nodejs", "vertx"}; - - private ProfanityDetector() { - } - - /** - * Detects if a message contains one of the profane words. - * - * @param message a message to check. - */ - static void detectProfanity(String message) { - if (message == null) { - return; - } - message = message.toLowerCase(); - for (String bannedTerm : BANNED_TERMS) { - if (message.contains(bannedTerm)) { - throw new ProfanityException(bannedTerm); - } - } - } -} diff --git a/examples/webserver/comment-aas/src/main/java/io/helidon/examples/webserver/comments/ProfanityException.java b/examples/webserver/comment-aas/src/main/java/io/helidon/examples/webserver/comments/ProfanityException.java deleted file mode 100644 index cc706be958a..00000000000 --- a/examples/webserver/comment-aas/src/main/java/io/helidon/examples/webserver/comments/ProfanityException.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.webserver.comments; - -/** - * Thrown to indicate that a message contains illegal argot word. - */ -public class ProfanityException extends IllegalArgumentException { - - private final String profanity; - - /** - * Creates new instance. - * - * @param profanity an illegal argot word. - */ - public ProfanityException(String profanity) { - super("Do not use such an ugly word as '" + obfuscate(profanity) + "'!"); - this.profanity = profanity; - } - - /** - * Returns an illegal argot word! - * - * @return an argot word - */ - public String getProfanity() { - return profanity; - } - - /** - * Returns an illegal argot word in obfuscated form! - * - * @return an argot word in obfuscated form - */ - public String getObfuscatedProfanity() { - return obfuscate(profanity); - } - - private static String obfuscate(String argot) { - if (argot == null || argot.length() < 2) { - return argot; - } - if (argot.length() == 2) { - return argot.charAt(0) + "*"; - } - return argot.charAt(0) + "*" + argot.charAt(argot.length() - 1); - } -} diff --git a/examples/webserver/comment-aas/src/main/java/io/helidon/examples/webserver/comments/package-info.java b/examples/webserver/comment-aas/src/main/java/io/helidon/examples/webserver/comments/package-info.java deleted file mode 100644 index a5dcff5e8f0..00000000000 --- a/examples/webserver/comment-aas/src/main/java/io/helidon/examples/webserver/comments/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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. - */ - -/** - * The COMMENTS-As-a-Service application example demonstrates Web Server in its integration role. - * It integrates various components including Configuration and Security. - * - *

        This WEB application provides possibility to store and read comment related to various topics. - */ -package io.helidon.examples.webserver.comments; diff --git a/examples/webserver/comment-aas/src/main/resources/application.yaml b/examples/webserver/comment-aas/src/main/resources/application.yaml deleted file mode 100644 index 80abf83fbee..00000000000 --- a/examples/webserver/comment-aas/src/main/resources/application.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# -# Copyright (c) 2017, 2021 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. -# - -webserver: - port: 8080 - -# If true then anonymous access is enabled. -anonymous-enabled: true diff --git a/examples/webserver/comment-aas/src/test/java/io/helidon/examples/webserver/comments/CommentsServiceTest.java b/examples/webserver/comment-aas/src/test/java/io/helidon/examples/webserver/comments/CommentsServiceTest.java deleted file mode 100644 index 17d7e0b61ff..00000000000 --- a/examples/webserver/comment-aas/src/test/java/io/helidon/examples/webserver/comments/CommentsServiceTest.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.webserver.comments; - -import io.helidon.common.media.type.MediaTypes; -import io.helidon.http.Status; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.http.HttpRouting; -import io.helidon.webserver.testing.junit5.DirectClient; -import io.helidon.webserver.testing.junit5.RoutingTest; -import io.helidon.webserver.testing.junit5.SetUpRoute; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.isEmptyString; - - -/** - * Tests {@link CommentsService}. - */ -@RoutingTest -public class CommentsServiceTest { - - private final DirectClient client; - - public CommentsServiceTest(DirectClient client) { - this.client = client; - } - - @SetUpRoute - static void setup(HttpRouting.Builder routing) { - Main.routing(routing, true); - } - - @Test - public void addAndGetComments() { - CommentsService service = new CommentsService(); - assertThat(service.listComments("one"), isEmptyString()); - assertThat(service.listComments("two"), isEmptyString()); - - service.addComment("aaa", null, "one"); - assertThat(service.listComments("one"), is("anonymous: aaa")); - assertThat(service.listComments("two"), isEmptyString()); - - service.addComment("bbb", "Foo", "one"); - assertThat(service.listComments("one"), is("anonymous: aaa\nFoo: bbb")); - assertThat(service.listComments("two"), isEmptyString()); - - service.addComment("bbb", "Bar", "two"); - assertThat(service.listComments("one"), is("anonymous: aaa\nFoo: bbb")); - assertThat(service.listComments("two"), is("Bar: bbb")); - } - - @Test - public void testRouting() { - try (Http1ClientResponse response = client.get("/comments/one").request()) { - assertThat(response.status(), is(Status.OK_200)); - } - try (Http1ClientResponse response = client.post("/comments/one") - .contentType(MediaTypes.TEXT_PLAIN) - .submit("aaa")) { - - assertThat(response.status(), is(Status.OK_200)); - } - - try (Http1ClientResponse response = client.get("/comments/one").request()) { - assertThat(response.status(), is(Status.OK_200)); - assertThat(response.entity().as(String.class), is("anonymous: aaa")); - } - } - -} diff --git a/examples/webserver/comment-aas/src/test/java/io/helidon/examples/webserver/comments/MainTest.java b/examples/webserver/comment-aas/src/test/java/io/helidon/examples/webserver/comments/MainTest.java deleted file mode 100644 index 06f8c043a63..00000000000 --- a/examples/webserver/comment-aas/src/test/java/io/helidon/examples/webserver/comments/MainTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.webserver.comments; - -import io.helidon.common.media.type.MediaTypes; -import io.helidon.http.Status; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.http.HttpRouting; -import io.helidon.webserver.testing.junit5.DirectClient; -import io.helidon.webserver.testing.junit5.RoutingTest; -import io.helidon.webserver.testing.junit5.SetUpRoute; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Tests {@link Main} class. - */ -@RoutingTest -public class MainTest { - - private final DirectClient client; - - public MainTest(DirectClient client) { - this.client = client; - } - - @SetUpRoute - static void setup(HttpRouting.Builder routing) { - Main.routing(routing, false); - } - - @Test - public void argot() { - try (Http1ClientResponse response = client.post("/comments/one") - .header(Main.USER_IDENTITY_HEADER, "Joe") - .contentType(MediaTypes.TEXT_PLAIN) - .submit("Spring framework is the BEST!")) { - - assertThat(response.status(), is(Status.NOT_ACCEPTABLE_406)); - } - } - - @Test - public void anonymousDisabled() { - try (Http1ClientResponse response = client.get("/comment/one").request()) { - assertThat(response.status(), is(Status.FORBIDDEN_403)); - } - } -} diff --git a/examples/webserver/echo/pom.xml b/examples/webserver/echo/pom.xml deleted file mode 100644 index 9228084dd70..00000000000 --- a/examples/webserver/echo/pom.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - - io.helidon.examples.webserver - helidon-examples-webserver-echo - Helidon Examples WebServer Echo - - - io.helidon.examples.webserver.echo.EchoMain - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webclient - helidon-webclient - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/webserver/echo/src/main/java/io/helidon/examples/webserver/echo/EchoClient.java b/examples/webserver/echo/src/main/java/io/helidon/examples/webserver/echo/EchoClient.java deleted file mode 100644 index 0460ff49fe3..00000000000 --- a/examples/webserver/echo/src/main/java/io/helidon/examples/webserver/echo/EchoClient.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2022, 2024 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.webserver.echo; - -import io.helidon.http.Header; -import io.helidon.http.HeaderValues; -import io.helidon.http.Headers; -import io.helidon.webclient.api.HttpClientRequest; -import io.helidon.webclient.api.HttpClientResponse; -import io.helidon.webclient.api.WebClient; - -/** - * A client that invokes the echo server. - */ -public class EchoClient { - private static final Header HEADER = HeaderValues.create("MY-HEADER", "header-value"); - private static final Header HEADERS = HeaderValues.create("MY-HEADERS", "ha", "hb", "hc"); - - private EchoClient() { - } - - /** - * Main method. - * - * @param args ignored - */ - public static void main(String[] args) { - WebClient client = WebClient.create(); - - HttpClientRequest request = client.get("http://localhost:8080/echo;param={param}/{name}"); - - try (HttpClientResponse response = request.pathParam("name", "param-placeholder") - .pathParam("param", "path-param-placeholder") - .queryParam("query-param", "single_value") - .queryParam("query-params", "a", "b", "c") - .header(HEADER) - .header(HEADERS) - .request()) { - - Headers headers = response.headers(); - for (Header header : headers) { - System.out.println("Header: " + header.name() + "=" + header.get()); - } - System.out.println("Entity:"); - System.out.println(response.as(String.class)); - } - } -} diff --git a/examples/webserver/echo/src/main/java/io/helidon/examples/webserver/echo/EchoMain.java b/examples/webserver/echo/src/main/java/io/helidon/examples/webserver/echo/EchoMain.java deleted file mode 100644 index 22d05c872cc..00000000000 --- a/examples/webserver/echo/src/main/java/io/helidon/examples/webserver/echo/EchoMain.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.webserver.echo; - -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Set; - -import io.helidon.common.parameters.Parameters; -import io.helidon.common.uri.UriQuery; -import io.helidon.http.Header; -import io.helidon.http.Headers; -import io.helidon.http.RoutedPath; -import io.helidon.http.Status; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -/** - * Echo example. - */ -public class EchoMain { - private EchoMain() { - } - - /** - * Main method. - * - * @param args ignored - */ - public static void main(String[] args) { - LogConfig.configureRuntime(); - - WebServer.builder() - .port(8080) - .host("127.0.0.1") - .routing(router -> router - .get("/echo/{param}", EchoMain::echo) - ) - .build() - .start(); - } - - private static void echo(ServerRequest req, ServerResponse res) { - RoutedPath path = req.path(); - UriQuery query = req.query(); - Headers headers = req.headers(); - - Parameters pathParams = path.matrixParameters(); - Parameters templateParams = path.pathParameters(); - Set queryNames = query.names(); - - for (String pathParamName : pathParams.names()) { - res.header("R-PATH_PARAM_" + pathParamName, pathParams.get(pathParamName)); - } - - for (String paramName : templateParams.names()) { - res.header("R-PATH_" + paramName, templateParams.get(paramName)); - } - - for (String queryName : queryNames) { - res.header("R-QUERY_" + queryName, query.all(queryName).toString()); - } - - for (Header header : headers) { - res.header("R-" + header.name(), header.allValues().toString()); - } - - try (InputStream inputStream = req.content().inputStream(); - OutputStream outputStream = res.outputStream()) { - inputStream.transferTo(outputStream); - } catch (Exception e) { - res.status(Status.INTERNAL_SERVER_ERROR_500).send("failed: " + e.getMessage()); - } - } -} diff --git a/examples/webserver/echo/src/main/java/io/helidon/examples/webserver/echo/package-info.java b/examples/webserver/echo/src/main/java/io/helidon/examples/webserver/echo/package-info.java deleted file mode 100644 index 10384932449..00000000000 --- a/examples/webserver/echo/src/main/java/io/helidon/examples/webserver/echo/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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. - */ - -/** - * Echo example. - */ -package io.helidon.examples.webserver.echo; diff --git a/examples/webserver/fault-tolerance/pom.xml b/examples/webserver/fault-tolerance/pom.xml deleted file mode 100644 index 7149794a0ea..00000000000 --- a/examples/webserver/fault-tolerance/pom.xml +++ /dev/null @@ -1,80 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - - io.helidon.examples.webserver - helidon-examples-webserver-fault-tolerance - Helidon Examples WebServer FT - - - Application demonstrates Fault tolerance used in webserver. - - - - io.helidon.examples.webserver.faulttolerance.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.fault-tolerance - helidon-fault-tolerance - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/webserver/fault-tolerance/src/main/java/io/helidon/examples/webserver/faulttolerance/FtService.java b/examples/webserver/fault-tolerance/src/main/java/io/helidon/examples/webserver/faulttolerance/FtService.java deleted file mode 100644 index ae68ebde626..00000000000 --- a/examples/webserver/fault-tolerance/src/main/java/io/helidon/examples/webserver/faulttolerance/FtService.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.webserver.faulttolerance; - -import java.time.Duration; -import java.util.concurrent.atomic.AtomicInteger; - -import io.helidon.faulttolerance.Async; -import io.helidon.faulttolerance.Bulkhead; -import io.helidon.faulttolerance.CircuitBreaker; -import io.helidon.faulttolerance.Fallback; -import io.helidon.faulttolerance.Retry; -import io.helidon.faulttolerance.Timeout; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -/** - * Simple service to demonstrate fault tolerance. - */ -public class FtService implements HttpService { - - private final Async async; - private final Bulkhead bulkhead; - private final CircuitBreaker breaker; - private final Fallback fallback; - private final Retry retry; - private final Timeout timeout; - - FtService() { - this.async = Async.create(); - this.bulkhead = Bulkhead.builder() - .queueLength(1) - .limit(1) - .name("helidon-example-bulkhead") - .build(); - this.breaker = CircuitBreaker.builder() - .volume(4) - .errorRatio(40) - .successThreshold(1) - .delay(Duration.ofSeconds(5)) - .build(); - this.fallback = Fallback.create(b -> b.fallback(this::fallbackToMethod)); - this.retry = Retry.builder() - .retryPolicy(Retry.DelayingRetryPolicy.noDelay(3)) - .build(); - this.timeout = Timeout.create(Duration.ofMillis(100)); - } - - @Override - public void routing(HttpRules rules) { - rules.get("/async", this::asyncHandler) - .get("/bulkhead/{millis}", this::bulkheadHandler) - .get("/circuitBreaker/{success}", this::circuitBreakerHandler) - .get("/fallback/{success}", this::fallbackHandler) - .get("/retry/{count}", this::retryHandler) - .get("/timeout/{millis}", this::timeoutHandler); - } - - private void timeoutHandler(ServerRequest request, ServerResponse response) { - long sleep = Long.parseLong(request.path().pathParameters().get("millis")); - response.send(timeout.invoke(() -> sleep(sleep))); - } - - private void retryHandler(ServerRequest request, ServerResponse response) { - int count = Integer.parseInt(request.path().pathParameters().get("count")); - - AtomicInteger call = new AtomicInteger(1); - AtomicInteger failures = new AtomicInteger(); - - String msg = retry.invoke(() -> { - int current = call.getAndIncrement(); - if (current < count) { - failures.incrementAndGet(); - return failure(); - } - return "calls/failures: " + current + "/" + failures.get(); - }); - response.send(msg); - } - - private void fallbackHandler(ServerRequest request, ServerResponse response) { - boolean success = "true".equalsIgnoreCase(request.path().pathParameters().get("success")); - if (success) { - response.send(fallback.invoke(this::data)); - } else { - response.send(fallback.invoke(this::failure)); - } - } - - private void circuitBreakerHandler(ServerRequest request, ServerResponse response) { - boolean success = "true".equalsIgnoreCase(request.path().pathParameters().get("success")); - if (success) { - response.send(breaker.invoke(this::data)); - } else { - response.send(breaker.invoke(this::failure)); - } - } - - private void bulkheadHandler(ServerRequest request, ServerResponse response) { - long sleep = Long.parseLong(request.path().pathParameters().get("millis")); - response.send(bulkhead.invoke(() -> sleep(sleep))); - } - - private void asyncHandler(ServerRequest request, ServerResponse response) { - response.send(async.invoke(this::data).join()); - } - - private String failure() { - throw new RuntimeException("failure"); - } - - private String sleep(long sleepMillis) { - try { - Thread.sleep(sleepMillis); - } catch (InterruptedException ignored) { - } - return "Slept for " + sleepMillis + " ms"; - } - - private String data() { - try { - Thread.sleep(100); - } catch (InterruptedException ignored) { - } - return "blocked for 100 millis"; - } - - private String fallbackToMethod(Throwable e) { - return "Failed back because of " + e.getMessage(); - } - -} diff --git a/examples/webserver/fault-tolerance/src/main/java/io/helidon/examples/webserver/faulttolerance/Main.java b/examples/webserver/fault-tolerance/src/main/java/io/helidon/examples/webserver/faulttolerance/Main.java deleted file mode 100644 index c2e15421a55..00000000000 --- a/examples/webserver/fault-tolerance/src/main/java/io/helidon/examples/webserver/faulttolerance/Main.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.webserver.faulttolerance; - -import io.helidon.faulttolerance.BulkheadException; -import io.helidon.faulttolerance.CircuitBreakerOpenException; -import io.helidon.faulttolerance.TimeoutException; -import io.helidon.http.Status; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.http.HttpRouting; - -/** - * Main class of Fault tolerance example. - */ -public final class Main { - // utility class - private Main() { - } - - /** - * Start the example. - * - * @param args start arguments are ignored - */ - public static void main(String[] args) { - LogConfig.configureRuntime(); - - WebServerConfig.Builder builder = WebServer.builder().port(8079); - setup(builder); - WebServer server = builder.build().start(); - - System.out.println("Server started on " + "http://localhost:" + server.port()); - } - - static void setup(WebServerConfig.Builder server) { - server.routing(Main::routing); - } - - static void routing(HttpRouting.Builder routing) { - routing.register("/ft", new FtService()) - .error(BulkheadException.class, - (req, res, ex) -> res.status(Status.SERVICE_UNAVAILABLE_503).send("bulkhead")) - .error(CircuitBreakerOpenException.class, - (req, res, ex) -> res.status(Status.SERVICE_UNAVAILABLE_503).send("circuit breaker")) - .error(TimeoutException.class, - (req, res, ex) -> res.status(Status.REQUEST_TIMEOUT_408).send("timeout")) - .error(Throwable.class, - (req, res, ex) -> res.status(Status.INTERNAL_SERVER_ERROR_500) - .send(ex.getClass().getName() + ": " + ex.getMessage())); - } -} diff --git a/examples/webserver/fault-tolerance/src/main/java/io/helidon/examples/webserver/faulttolerance/package-info.java b/examples/webserver/fault-tolerance/src/main/java/io/helidon/examples/webserver/faulttolerance/package-info.java deleted file mode 100644 index 44a42011ecb..00000000000 --- a/examples/webserver/fault-tolerance/src/main/java/io/helidon/examples/webserver/faulttolerance/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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 of Fault Tolerance usage in webserver. - */ -package io.helidon.examples.webserver.faulttolerance; diff --git a/examples/webserver/fault-tolerance/src/main/resources/logging.properties b/examples/webserver/fault-tolerance/src/main/resources/logging.properties deleted file mode 100644 index ddbc8d6521d..00000000000 --- a/examples/webserver/fault-tolerance/src/main/resources/logging.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2020, 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. -# - -handlers=io.helidon.logging.jul.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=[%1$tc] %4$s: %2$s - %5$s %6$s%n -.level=INFO -io.helidon.microprofile.server.level=INFO diff --git a/examples/webserver/fault-tolerance/src/test/java/io/helidon/examples/webserver/faulttolerance/MainTest.java b/examples/webserver/fault-tolerance/src/test/java/io/helidon/examples/webserver/faulttolerance/MainTest.java deleted file mode 100644 index 5cbc14f71fe..00000000000 --- a/examples/webserver/fault-tolerance/src/test/java/io/helidon/examples/webserver/faulttolerance/MainTest.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.webserver.faulttolerance; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -import io.helidon.http.Status; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.http.HttpRouting; -import io.helidon.webserver.testing.junit5.DirectClient; -import io.helidon.webserver.testing.junit5.RoutingTest; -import io.helidon.webserver.testing.junit5.SetUpRoute; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -@RoutingTest -class MainTest { - - private final DirectClient client; - - MainTest(DirectClient client) { - this.client = client; - } - - @SetUpRoute - static void setup(HttpRouting.Builder routing) { - Main.routing(routing); - } - - @Test - void testAsync() { - try (Http1ClientResponse response = client.get("/ft/async").request()) { - assertThat(response.as(String.class), is("blocked for 100 millis")); - } - } - - @Test - void testBulkhead() throws InterruptedException { - // bulkhead is configured for limit of 1 and queue of 1, so third - // request should fail - - ExecutorService executor = Executors.newFixedThreadPool(2); - executor.submit(() -> client.get("/ft/bulkhead/10000").request().close()); - executor.submit(() -> client.get("/ft/bulkhead/10000").request().close()); - - // I want to make sure the above is connected - Thread.sleep(300); - - try (Http1ClientResponse response = client.get("/ft/bulkhead/10000").request()) { - // registered an error handler in Main - assertThat(response.status(), is(Status.SERVICE_UNAVAILABLE_503)); - assertThat(response.as(String.class), is("bulkhead")); - } finally { - executor.close(); - } - } - - @Test - void testCircuitBreaker() { - try (Http1ClientResponse response = client.get("/ft/circuitBreaker/true").request()) { - assertThat(response.as(String.class), is("blocked for 100 millis")); - } - - // error ratio is 20% within 10 request - // should work after first - try (Http1ClientResponse ignored = client.get("/ft/circuitBreaker/false").request(); - Http1ClientResponse response = client.get("/ft/circuitBreaker/true").request()) { - - assertThat(response.as(String.class), is("blocked for 100 millis")); - } - - // should open after second - client.get("/ft/circuitBreaker/false").request().close(); - - try (Http1ClientResponse response = client.get("/ft/circuitBreaker/true").request()) { - - // registered an error handler in Main - assertThat(response.status(), is(Status.SERVICE_UNAVAILABLE_503)); - assertThat(response.as(String.class), is("circuit breaker")); - } - } - - @Test - void testFallback() { - try (Http1ClientResponse response = client.get("/ft/fallback/true").request()) { - assertThat(response.as(String.class), is("blocked for 100 millis")); - } - - try (Http1ClientResponse response = client.get("/ft/fallback/false").request()) { - assertThat(response.as(String.class), is("Failed back because of failure")); - } - } - - @Test - void testRetry() { - try (Http1ClientResponse response = client.get("/ft/retry/1").request()) { - assertThat(response.as(String.class), is("calls/failures: 1/0")); - } - - try (Http1ClientResponse response = client.get("/ft/retry/2").request()) { - assertThat(response.as(String.class), is("calls/failures: 2/1")); - } - - try (Http1ClientResponse response = client.get("/ft/retry/3").request()) { - assertThat(response.as(String.class), is("calls/failures: 3/2")); - } - - try (Http1ClientResponse response = client.get("/ft/retry/4").request()) { - // no error handler specified - assertThat(response.status(), is(Status.INTERNAL_SERVER_ERROR_500)); - assertThat(response.as(String.class), is("java.lang.RuntimeException: failure")); - } - } - - @Test - void testTimeout() { - try (Http1ClientResponse response = client.get("/ft/timeout/10").request()) { - assertThat(response.as(String.class), is("Slept for 10 ms")); - } - - try (Http1ClientResponse response = client.get("/ft/timeout/1000").request()) { - // error handler specified in Main - assertThat(response.status(), is(Status.REQUEST_TIMEOUT_408)); - assertThat(response.as(String.class), is("timeout")); - } - } -} \ No newline at end of file diff --git a/examples/webserver/imperative/pom.xml b/examples/webserver/imperative/pom.xml deleted file mode 100644 index 11a672c0edc..00000000000 --- a/examples/webserver/imperative/pom.xml +++ /dev/null @@ -1,93 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - - io.helidon.examples.webserver - helidon-examples-webserver-imperative - Helidon Examples WebServer Imperative - Example of imperative ("pure" programmatic) approach using Helidon SE - - - io.helidon.examples.webserver.imperative.ImperativeMain - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.config - helidon-config-yaml - - - io.helidon.logging - helidon-logging-jul - runtime - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.apache.maven.plugins - maven-failsafe-plugin - - - - integration-test - verify - - - - - - - diff --git a/examples/webserver/imperative/src/main/java/io/helidon/examples/webserver/imperative/ImperativeMain.java b/examples/webserver/imperative/src/main/java/io/helidon/examples/webserver/imperative/ImperativeMain.java deleted file mode 100644 index a7ee931d646..00000000000 --- a/examples/webserver/imperative/src/main/java/io/helidon/examples/webserver/imperative/ImperativeMain.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2023 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.webserver.imperative; - -import io.helidon.config.Config; -import io.helidon.http.Method; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.http.HttpRouting; - -/** - * Main class of this example, starts the server. - */ -public final class ImperativeMain { - private ImperativeMain() { - } - - /** - * Start the example. - * - * @param args ignored - */ - public static void main(String[] args) { - Config config = Config.create(); - Config.global(config); - - WebServer server = WebServer.create(ws -> ws.config(config.get("server")) - .routing(ImperativeMain::routing)) - .start(); - - System.out.println("Server started. Server configuration: " + server.prototype()); - } - - private static void routing(HttpRouting.Builder routing) { - Method list = Method.create("LIST"); - - routing.get("/", (req, res) -> res.send("Hello World!")) - .route(list, "/", (req, res) -> res.send("lll")) - .route(list, (req, res) -> res.send("listed")); - } -} diff --git a/examples/webserver/imperative/src/main/java/io/helidon/examples/webserver/imperative/package-info.java b/examples/webserver/imperative/src/main/java/io/helidon/examples/webserver/imperative/package-info.java deleted file mode 100644 index 977a0741717..00000000000 --- a/examples/webserver/imperative/src/main/java/io/helidon/examples/webserver/imperative/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2023 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 showing usage of HTTP web-server with pure imperative programming (no injection, no inversion of control). - */ -package io.helidon.examples.webserver.imperative; diff --git a/examples/webserver/imperative/src/main/resources/application.yaml b/examples/webserver/imperative/src/main/resources/application.yaml deleted file mode 100644 index 0a295e0ad93..00000000000 --- a/examples/webserver/imperative/src/main/resources/application.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2023 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: - host: "localhost" - port: 8080 - sockets: - - name: "https" - host: "localhost" - port: 8081 diff --git a/examples/webserver/multiport/README.md b/examples/webserver/multiport/README.md deleted file mode 100644 index e7709a456cd..00000000000 --- a/examples/webserver/multiport/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# Helidon WebServer Multiple Port Example - -It is common when deploying a microservice to run your service on -multiple ports so that you can control the visibility of your -service's endpoints. For example, you might want to use three ports: - -- 8080: public REST endpoints of application -- 8081: private REST endpoints of application -- 8082: admin endpoints for health, metrics, etc. - -This lets you expose only the public endpoints via your -ingress controller or load balancer. - -This example shows a Helidon application running on three ports -as described above. - -The ports are configured in `application.yaml` by using named sockets. - -Separate routing is defined for each named socket in `Main.java` - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-webserver-multiport.jar -``` -## Exercise the application - -``` -curl -X GET http://localhost:8080/hello - -curl -X GET http://localhost:8081/private/hello - -curl -X GET http://localhost:8082/observe/health - -curl -X GET http://localhost:8082/observe/metrics -``` diff --git a/examples/webserver/multiport/pom.xml b/examples/webserver/multiport/pom.xml deleted file mode 100644 index 9c6072db269..00000000000 --- a/examples/webserver/multiport/pom.xml +++ /dev/null @@ -1,106 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.webserver - helidon-examples-webserver-multiport - Helidon Examples WebServer Multiple Ports - - - io.helidon.webserver.examples.multiport.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver.observe - helidon-webserver-observe - - - io.helidon.config - helidon-config-yaml - - - io.helidon.webserver.observe - helidon-webserver-observe-health - - - io.helidon.health - helidon-health-checks - - - io.helidon.webserver.observe - helidon-webserver-observe-metrics - - - io.helidon.metrics - helidon-metrics-system-meters - - - io.helidon.logging - helidon-logging-jul - runtime - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.junit.jupiter - junit-jupiter-params - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/webserver/multiport/src/main/java/io/helidon/webserver/examples/multiport/Main.java b/examples/webserver/multiport/src/main/java/io/helidon/webserver/examples/multiport/Main.java deleted file mode 100644 index 6a6cf489def..00000000000 --- a/examples/webserver/multiport/src/main/java/io/helidon/webserver/examples/multiport/Main.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.webserver.examples.multiport; - -import io.helidon.config.Config; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.http.HttpRouting; - -/** - * 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) { - // load logging configuration - LogConfig.configureRuntime(); - - // By default, this will pick up application.yaml from the classpath - Config config = Config.create(); - Config.global(config); - - WebServer server = WebServer.builder() - .config(config.get("server")) - .update(Main::setup) - .build() - .start(); - - System.out.println("WEB server is up! http://localhost:" + server.port()); - } - - /** - * Set up the server. - */ - static void setup(WebServerConfig.Builder server) { - // Build server using three ports: - // default public port, admin port, private port - server.routing(Main::publicRouting) - .routing("private", Main::privateSocket); - } - - /** - * Set up private socket. - */ - static void privateSocket(HttpRouting.Builder routing) { - routing.get("/private/hello", (req, res) -> res.send("Private Hello!!")); - } - - /** - * Set up public routing. - */ - static void publicRouting(HttpRouting.Builder routing) { - routing.get("/hello", (req, res) -> res.send("Public Hello!!")); - } -} diff --git a/examples/webserver/multiport/src/main/java/io/helidon/webserver/examples/multiport/package-info.java b/examples/webserver/multiport/src/main/java/io/helidon/webserver/examples/multiport/package-info.java deleted file mode 100644 index 9933f12e863..00000000000 --- a/examples/webserver/multiport/src/main/java/io/helidon/webserver/examples/multiport/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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. - */ -/** - * Application that exposes multiple ports. - */ -package io.helidon.webserver.examples.multiport; diff --git a/examples/webserver/multiport/src/main/resources/application.yaml b/examples/webserver/multiport/src/main/resources/application.yaml deleted file mode 100644 index e94e7a51231..00000000000 --- a/examples/webserver/multiport/src/main/resources/application.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (c) 2021, 2023 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: "localhost" - sockets: - - name: "private" - port: 8081 - bind-address: "localhost" - - name: "admin" - port: 8082 - bind-address: "localhost" - features: - observe: - sockets: "admin" diff --git a/examples/webserver/multiport/src/main/resources/logging.properties b/examples/webserver/multiport/src/main/resources/logging.properties deleted file mode 100644 index c916a0505a0..00000000000 --- a/examples/webserver/multiport/src/main/resources/logging.properties +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright (c) 2021, 2024 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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 diff --git a/examples/webserver/multiport/src/test/java/io/helidon/webserver/examples/multiport/MainTest.java b/examples/webserver/multiport/src/test/java/io/helidon/webserver/examples/multiport/MainTest.java deleted file mode 100644 index 2f70692955a..00000000000 --- a/examples/webserver/multiport/src/test/java/io/helidon/webserver/examples/multiport/MainTest.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.webserver.examples.multiport; - -import java.util.stream.Stream; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.http.Status; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -@ServerTest -public class MainTest { - - private final Http1Client client; - private final int publicPort; - private final int privatePort; - private final int adminPort; - - public MainTest(WebServer server) { - client = Http1Client.builder().build(); - publicPort = server.port(); - privatePort = server.port("private"); - adminPort = server.port("admin"); - } - - int port(Params params) { - return switch (params.socket) { - case PUBLIC -> publicPort; - case ADMIN -> adminPort; - case PRIVATE -> privatePort; - }; - } - - @SetUpServer - public static void setup(WebServerConfig.Builder server) { - // Use test configuration so we can have ports allocated dynamically - Config config = Config.just(ConfigSources.classpath("application-test.yaml")); - server.config(config.get("server")) - .update(Main::setup); - } - - static Stream initParams() { - final String PUBLIC_PATH = "/hello"; - final String PRIVATE_PATH = "/private/hello"; - final String HEALTH_PATH = "/health"; - final String METRICS_PATH = "/health"; - - return Stream.of( - new Params(Socket.PUBLIC, PUBLIC_PATH, Status.OK_200), - new Params(Socket.PUBLIC, PRIVATE_PATH, Status.NOT_FOUND_404), - new Params(Socket.PUBLIC, HEALTH_PATH, Status.NOT_FOUND_404), - new Params(Socket.PUBLIC, METRICS_PATH, Status.NOT_FOUND_404), - - new Params(Socket.PRIVATE, PUBLIC_PATH, Status.NOT_FOUND_404), - new Params(Socket.PRIVATE, PRIVATE_PATH, Status.OK_200), - new Params(Socket.PRIVATE, HEALTH_PATH, Status.NOT_FOUND_404), - new Params(Socket.PRIVATE, METRICS_PATH, Status.NOT_FOUND_404), - - new Params(Socket.ADMIN, PUBLIC_PATH, Status.NOT_FOUND_404), - new Params(Socket.ADMIN, PRIVATE_PATH, Status.NOT_FOUND_404), - new Params(Socket.ADMIN, HEALTH_PATH, Status.OK_200), - new Params(Socket.ADMIN, METRICS_PATH, Status.OK_200)); - } - - @MethodSource("initParams") - @ParameterizedTest - public void portAccessTest(Params params) { - // Verifies we can access endpoints only on the proper port - client.get() - .uri("http://localhost:" + port(params)) - .path(params.path) - .request() - .close(); - } - - @Test - public void portTest() { - try (Http1ClientResponse response = client.get() - .uri("http://localhost:" + publicPort) - .path("/hello") - .request()) { - assertThat(response.as(String.class), is("Public Hello!!")); - } - - try (Http1ClientResponse response = client.get() - .uri("http://localhost:" + privatePort) - .path("/private/hello") - .request()) { - assertThat(response.as(String.class), is("Private Hello!!")); - } - } - - private record Params(Socket socket, String path, Status httpStatus) { - - @Override - public String toString() { - return path + " @" + socket + " should return " + httpStatus; - } - } - - private enum Socket { - PUBLIC, - ADMIN, - PRIVATE - } - -} diff --git a/examples/webserver/multiport/src/test/resources/application-test.yaml b/examples/webserver/multiport/src/test/resources/application-test.yaml deleted file mode 100644 index d7a80acca0b..00000000000 --- a/examples/webserver/multiport/src/test/resources/application-test.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2021 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: 0 - host: "localhost" - sockets: - - name: "private" - port: 0 - bind-address: "localhost" - - name: "admin" - port: 0 - bind-address: "localhost" diff --git a/examples/webserver/mutual-tls/README.md b/examples/webserver/mutual-tls/README.md deleted file mode 100644 index 06619016737..00000000000 --- a/examples/webserver/mutual-tls/README.md +++ /dev/null @@ -1,47 +0,0 @@ -# Mutual TLS Example - -This application demonstrates use of client certificates to -authenticate HTTP client. - -## Build - -```shell -mvn package -``` - -## Run - -Run the _config_ variant (default) of the application: - -```shell -java -jar target/helidon-examples-webserver-mutual-tls.jar -``` - -Run the _programmatic_ variant of the application: - -```shell -mvn exec:java -Dexec.mainClass=io.helidon.examples.webserver.mtls.ServerBuilderMain -``` - -## Exercise the application - -Using `curl`: - -```shell -openssl pkcs12 -in src/main/resources/client.p12 -nodes -legacy -passin pass:changeit -nokeys -out /tmp/chain.pem -openssl pkcs12 -in src/main/resources/client.p12 -nodes -legacy -passin pass:changeit -nokeys -cacerts -out /tmp/ca.pem -openssl pkcs12 -in src/main/resources/client.p12 -nodes -legacy -passin pass:changeit -nocerts -out /tmp/key.pem -curl --key /tmp/key.pem --cert /tmp/chain.pem --cacert /tmp/ca.pem https://localhost:443 --pass changeit -``` - -Using Helidon WebClient setup with configuration: - -```shell -mvn exec:java -Dexec.mainClass=io.helidon.examples.webserver.mtls.ClientConfigMain -``` - -Using Helidon WebClient setup programmatically: - -```shell -mvn exec:java -Dexec.mainClass=io.helidon.examples.webserver.mtls.ClientBuilderMain -``` diff --git a/examples/webserver/mutual-tls/automatic-store-generator.sh b/examples/webserver/mutual-tls/automatic-store-generator.sh deleted file mode 100644 index 35ff6449b2c..00000000000 --- a/examples/webserver/mutual-tls/automatic-store-generator.sh +++ /dev/null @@ -1,168 +0,0 @@ -#!/bin/bash -e -# -# Copyright (c) 2020, 2024 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. -# - -# Windows Mingwin fix for path resolving -#export MSYS_NO_PATHCONV=1 - -NAME="" -TYPE=PKCS12 -SINGLE=true - -createCertificatesAndStores() { - mkdir out - echo 'Generating new key stores...' - keytool -genkeypair -keyalg RSA -keysize 2048 -alias root-ca -dname "CN=$NAME-CA" -validity 21650 -keystore ca.jks -storepass changeit -keypass changeit -deststoretype pkcs12 -ext KeyUsage=digitalSignature,keyEncipherment,keyCertSign -ext ExtendedKeyUsage=serverAuth,clientAuth -ext BasicConstraints=ca:true,PathLen:3 - keytool -genkeypair -keyalg RSA -keysize 2048 -alias server -dname "CN=localhost" -validity 21650 -keystore server.jks -storepass changeit -keypass changeit -deststoretype pkcs12 - keytool -genkeypair -keyalg RSA -keysize 2048 -alias client -dname "C=CZ,CN=$NAME-client,OU=Prague,O=Oracle" -validity 21650 -keystore client.jks -storepass changeit -keypass changeit -deststoretype pkcs12 - echo 'Obtaining client and server certificates...' - keytool -exportcert -keystore client.jks -storepass changeit -alias client -rfc -file client.cer - keytool -exportcert -keystore server.jks -storepass changeit -alias server -rfc -file server.cer - echo 'Generating CSR for client and server...' - keytool -certreq -keystore server.jks -alias server -keypass changeit -storepass changeit -keyalg rsa -file server.csr - keytool -certreq -keystore client.jks -alias client -keypass changeit -storepass changeit -keyalg rsa -file client.csr - echo 'Obtaining CA pem and key...' - keytool -importkeystore -srckeystore ca.jks -destkeystore ca.p12 -srcstoretype jks -deststoretype pkcs12 -srcstorepass changeit -deststorepass changeit - openssl pkcs12 -in ca.p12 -out ca.key -nocerts -passin pass:changeit -passout pass:changeit - openssl pkcs12 -in ca.p12 -out ca.pem -nokeys -passin pass:changeit -passout pass:changeit - echo 'Signing client and server certificates...' - openssl x509 -req -in client.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out client-signed.cer -days 21650 -passin pass:changeit - openssl x509 -req -in server.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out server-signed.cer -sha256 -days 21650 -passin pass:changeit - echo 'Replacing server and client certificates with the signed ones...' - keytool -importkeystore -srckeystore client.jks -destkeystore client.p12 -srcstoretype jks -deststoretype pkcs12 -srcstorepass changeit -deststorepass changeit - openssl pkcs12 -in client.p12 -nodes -out client-private.key -nocerts -passin pass:changeit - openssl pkcs12 -export -in client-signed.cer -inkey client-private.key -out client-signed.p12 -name client -passout pass:changeit - keytool -delete -alias client -keystore client.jks -storepass changeit - keytool -importkeystore -srckeystore client-signed.p12 -srcstoretype PKCS12 -destkeystore client.jks -srcstorepass changeit -deststorepass changeit - keytool -importkeystore -srckeystore server.jks -destkeystore server.p12 -srcstoretype jks -deststoretype pkcs12 -srcstorepass changeit -deststorepass changeit - openssl pkcs12 -in server.p12 -nodes -out server-private.key -nocerts -passin pass:changeit - openssl pkcs12 -export -in server-signed.cer -inkey server-private.key -out server-signed.p12 -name server -passout pass:changeit - keytool -delete -alias server -keystore server.jks -storepass changeit - keytool -importkeystore -srckeystore server-signed.p12 -srcstoretype PKCS12 -destkeystore server.jks -srcstorepass changeit -deststorepass changeit - - echo "Importing CA cert to the client and server stores..." - if [ "${SINGLE}" = true ] ; then - keytool -v -trustcacerts -keystore client.jks -importcert -file ca.pem -alias root-ca -storepass changeit -noprompt - keytool -v -trustcacerts -keystore server.jks -importcert -file ca.pem -alias root-ca -storepass changeit -noprompt - else - keytool -v -trustcacerts -keystore client-truststore.jks -importcert -file ca.pem -alias root-ca -storepass changeit -noprompt - keytool -v -trustcacerts -keystore server-truststore.jks -importcert -file ca.pem -alias root-ca -storepass changeit -noprompt - fi - - echo "Changing aliases to 1..." - keytool -changealias -alias server -destalias 1 -keypass changeit -keystore server.jks -storepass changeit - keytool -changealias -alias client -destalias 1 -keypass changeit -keystore client.jks -storepass changeit - - echo "Generating requested type of stores..." - if [ "$TYPE" = PKCS12 ] || [ "$TYPE" = P12 ] ; then - keytool -importkeystore -srckeystore client.jks -destkeystore out/client.p12 -srcstoretype JKS -deststoretype PKCS12 -srcstorepass changeit -deststorepass changeit - keytool -importkeystore -srckeystore server.jks -destkeystore out/server.p12 -srcstoretype JKS -deststoretype PKCS12 -srcstorepass changeit -deststorepass changeit - if [ "${SINGLE}" = false ] ; then - keytool -importkeystore -srckeystore server-truststore.jks -destkeystore out/server-truststore.p12 -srcstoretype JKS -deststoretype PKCS12 -srcstorepass changeit -deststorepass changeit - keytool -importkeystore -srckeystore client-truststore.jks -destkeystore out/client-truststore.p12 -srcstoretype JKS -deststoretype PKCS12 -srcstorepass changeit -deststorepass changeit - fi - else - mv client.jks out/client.jks - mv server.jks out/server.jks - if [ "${SINGLE}" = false ] ; then - mv client-truststore.jks out/client-truststore.jks - mv server-truststore.jks out/server-truststore.jks - fi - fi -} - -removeAllPreviouslyCreatedStores() { - echo "Removing all of previously created items..." - - rm -fv ca.key - rm -fv ca.jks - rm -fv ca.p12 - rm -fv ca.pem - rm -fv ca.srl - rm -fv server.jks - rm -fv server.cer - rm -fv server.csr - rm -fv server.p12 - rm -fv server-private.key - rm -fv server-signed.cer - rm -fv server-signed.p12 - rm -fv server-truststore.jks - rm -fv client.cer - rm -fv client.csr - rm -fv client.p12 - rm -fv client-private.key - rm -fv client-signed.cer - rm -fv client-signed.p12 - rm -fv client.jks - rm -fv client-truststore.jks - rm -rf out - - echo "Clean up finished" -} - -while [ "$1" != "" ]; do - case $1 in - -n | --name) - shift - NAME=$1 - ;; - -t | --type ) - shift - TYPE="${1}" - ;; - -s | --single ) - shift - SINGLE="${1}" - ;; - -h | --help ) - echo "Some cool help" - exit - ;; - * ) - echo "ERROR: Invalid parameter ${1}" - exit 1 - esac - shift -done -if [ -z "${NAME}" ]; then - echo "ERROR: Please specify the name of Organization/Application by parameter -n | --name" - exit 1 -else - echo "Generating certs for Organization/Application ${NAME}" -fi -case ${TYPE} in - JKS | P12 | PKCS12 ) - echo "Output file will be of type ${TYPE}" - ;; - *) - echo "ERROR: Invalid output type ${TYPE}" - echo "Only JKS | P12 | PKCS12 supported" - return 1 -esac -case ${SINGLE} in - true) - echo "Truststore and private key will be in single file" - ;; - false) - echo "Truststore and private key will be in separate files" - ;; - *) - echo "ERROR: Only value true/false valid in single parameter! Current ${SINGLE}" - exit 1 -esac - -removeAllPreviouslyCreatedStores -createCertificatesAndStores diff --git a/examples/webserver/mutual-tls/pom.xml b/examples/webserver/mutual-tls/pom.xml deleted file mode 100644 index 887d49836e2..00000000000 --- a/examples/webserver/mutual-tls/pom.xml +++ /dev/null @@ -1,88 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.webserver - helidon-examples-webserver-mutual-tls - Helidon Examples WebServer Mutual TLS - - - Application demonstrates the use of mutual TLS with WebServer and WebClient - - - - io.helidon.examples.webserver.mtls.ServerConfigMain - - - - - - io.helidon.webclient - helidon-webclient - - - io.helidon.webserver - helidon-webserver - - - io.helidon.config - helidon-config-yaml - - - io.helidon.logging - helidon-logging-jul - runtime - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/webserver/mutual-tls/src/main/java/io/helidon/examples/webserver/mtls/ClientBuilderMain.java b/examples/webserver/mutual-tls/src/main/java/io/helidon/examples/webserver/mtls/ClientBuilderMain.java deleted file mode 100644 index 071d64631c9..00000000000 --- a/examples/webserver/mutual-tls/src/main/java/io/helidon/examples/webserver/mtls/ClientBuilderMain.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2020, 2024 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.webserver.mtls; - -import io.helidon.common.configurable.Resource; -import io.helidon.common.pki.Keys; -import io.helidon.common.tls.Tls; -import io.helidon.common.tls.TlsClientAuth; -import io.helidon.webclient.http1.Http1Client; - -/** - * Setting up {@link io.helidon.webclient.api.WebClient} to support mutual TLS via builder. - */ -public class ClientBuilderMain { - - private ClientBuilderMain() { - } - - /** - * Start the example. - * This example executes two requests by Helidon {@link io.helidon.webclient.api.WebClient} which are configured - * by the {@link io.helidon.webclient.api.WebClientConfig.Builder}. - *

        - * You have to execute either {@link ServerBuilderMain} or {@link ServerConfigMain} for this to work. - *

        - * If any of the ports has been changed, you have to update ports in this main method also. - * - * @param args start arguments are ignored - */ - public static void main(String[] args) { - Http1Client client = createClient(); - - System.out.println("Contacting unsecured endpoint!"); - System.out.println("Response: " + callUnsecured(client, 8080)); - - System.out.println("Contacting secured endpoint!"); - System.out.println("Response: " + callSecured(client, 443)); - } - - static Http1Client createClient() { - Keys keyConfig = Keys.builder() - .keystore(store -> store - .trustStore(true) - .keystore(Resource.create("client.p12")) - .passphrase("changeit")) - .build(); - return Http1Client.builder() - .tls(Tls.builder() - .endpointIdentificationAlgorithm("NONE") - .clientAuth(TlsClientAuth.REQUIRED) - .privateKey(keyConfig) - .privateKeyCertChain(keyConfig) - .trust(keyConfig) - .build()) - .build(); - } - - static String callUnsecured(Http1Client client, int port) { - return client.get("http://localhost:" + port) - .requestEntity(String.class); - } - - static String callSecured(Http1Client client, int port) { - return client.get("https://localhost:" + port) - .requestEntity(String.class); - } -} diff --git a/examples/webserver/mutual-tls/src/main/java/io/helidon/examples/webserver/mtls/ClientConfigMain.java b/examples/webserver/mutual-tls/src/main/java/io/helidon/examples/webserver/mtls/ClientConfigMain.java deleted file mode 100644 index fc7af1e35aa..00000000000 --- a/examples/webserver/mutual-tls/src/main/java/io/helidon/examples/webserver/mtls/ClientConfigMain.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.webserver.mtls; - -import io.helidon.config.Config; -import io.helidon.webclient.http1.Http1Client; - -/** - * Setting up {@link io.helidon.webclient.api.WebClient} to support mutual TLS via configuration. - */ -public class ClientConfigMain { - - private ClientConfigMain() { - } - - /** - * Start the example. - * This example executes two requests by Helidon {@link io.helidon.webclient.api.WebClient} which are configured - * by the configuration. - *

        - * You have to execute either {@link ServerBuilderMain} or {@link ServerConfigMain} for this to work. - *

        - * If any of the ports has been changed, you have to update ports in this main method also. - * - * @param args start arguments are ignored - */ - public static void main(String[] args) { - Config config = Config.create(); - Http1Client client = Http1Client.builder() - .config(config.get("client")) - .build(); - - System.out.println("Contacting unsecured endpoint!"); - System.out.println("Response: " + callUnsecured(client, 8080)); - - System.out.println("Contacting secured endpoint!"); - System.out.println("Response: " + callSecured(client, 443)); - - } - - static String callUnsecured(Http1Client client, int port) { - return client.get("http://localhost:" + port) - .requestEntity(String.class); - } - - static String callSecured(Http1Client client, int port) { - return client.get("https://localhost:" + port) - .requestEntity(String.class); - } -} diff --git a/examples/webserver/mutual-tls/src/main/java/io/helidon/examples/webserver/mtls/SecureService.java b/examples/webserver/mutual-tls/src/main/java/io/helidon/examples/webserver/mtls/SecureService.java deleted file mode 100644 index 04f7d924ff7..00000000000 --- a/examples/webserver/mutual-tls/src/main/java/io/helidon/examples/webserver/mtls/SecureService.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2023, 2024 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.webserver.mtls; - -import io.helidon.http.HeaderValues; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; - -import static io.helidon.http.HeaderNames.X_HELIDON_CN; - -class SecureService implements HttpService { - @Override - public void routing(HttpRules rules) { - rules.any((req, res) -> { - // close to avoid re-using cached connections on the client side - res.header(HeaderValues.CONNECTION_CLOSE); - res.send("Hello " + req.headers().get(X_HELIDON_CN).get() + "!"); - }); - } -} diff --git a/examples/webserver/mutual-tls/src/main/java/io/helidon/examples/webserver/mtls/ServerBuilderMain.java b/examples/webserver/mutual-tls/src/main/java/io/helidon/examples/webserver/mtls/ServerBuilderMain.java deleted file mode 100644 index 6f1878aa1d4..00000000000 --- a/examples/webserver/mutual-tls/src/main/java/io/helidon/examples/webserver/mtls/ServerBuilderMain.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2020, 2024 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.webserver.mtls; - -import io.helidon.common.configurable.Resource; -import io.helidon.common.pki.Keys; -import io.helidon.common.tls.TlsClientAuth; -import io.helidon.webserver.ListenerConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.http.HttpRouting; - -/** - * Setting up {@link WebServer} to support mutual TLS via builder. - */ -public class ServerBuilderMain { - - private ServerBuilderMain() { - } - - /** - * Start the example. - * This will start Helidon {@link WebServer} which is configured by the {@link WebServerConfig.Builder}. - * There will be two sockets running: - *

          - *
        • {@code 8080} - without TLS protection - *
        • {@code 443} - with TLS protection - *

        - * Both of the ports mentioned above are default ports for this example and can be changed by updating - * values in this method. - * - * @param args start arguments are ignored - */ - public static void main(String[] args) { - WebServerConfig.Builder builder = WebServer.builder() - .port(8080) - .putSocket("secured", socket -> socket.port(443)); - setup(builder); - WebServer server = builder.build().start(); - System.out.printf(""" - WebServer is up! - Unsecured: http://localhost:%1$d - Secured: https://localhost:%2$d - """, server.port(), server.port("secured")); - } - - static void setup(WebServerConfig.Builder server) { - server.routing(ServerBuilderMain::plainRouting) - .putSocket("secured", socket -> securedSocket(server, socket)); - } - - static void plainRouting(HttpRouting.Builder routing) { - routing.get("/", (req, res) -> res.send("Hello world unsecured!")); - } - - private static void securedSocket(WebServerConfig.Builder server, ListenerConfig.Builder socket) { - Keys keyConfig = Keys.builder() - .keystore(store -> store - .trustStore(true) - .keystore(Resource.create("server.p12")) - .passphrase("changeit")) - .build(); - - socket.from(server.sockets().get("secured")) - .tls(tls -> tls - .endpointIdentificationAlgorithm("NONE") - .clientAuth(TlsClientAuth.REQUIRED) - .trust(keyConfig) - .privateKey(keyConfig) - .privateKeyCertChain(keyConfig)) - .routing(routing -> routing - .register("/", new SecureService())); - } -} diff --git a/examples/webserver/mutual-tls/src/main/java/io/helidon/examples/webserver/mtls/ServerConfigMain.java b/examples/webserver/mutual-tls/src/main/java/io/helidon/examples/webserver/mtls/ServerConfigMain.java deleted file mode 100644 index dfc905f693f..00000000000 --- a/examples/webserver/mutual-tls/src/main/java/io/helidon/examples/webserver/mtls/ServerConfigMain.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.webserver.mtls; - -import io.helidon.config.Config; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.http.HttpRouting; - -/** - * Setting up {@link WebServer} to support mutual TLS via configuration. - */ -public class ServerConfigMain { - - private ServerConfigMain() { - } - - /** - * Start the example. - * This will start Helidon {@link WebServer} which is configured by the configuration. - * There will be two sockets running: - *

          - *
        • {@code 8080} - without TLS protection - *
        • {@code 443} - with TLS protection - *

        - * Both of the ports mentioned above are default ports for this example and can be changed via configuration file. - * - * @param args start arguments are ignored - */ - public static void main(String[] args) { - Config config = Config.create(); - WebServerConfig.Builder builder = WebServer.builder(); - setup(builder, config.get("server")); - WebServer server = builder.build().start(); - System.out.printf(""" - WebServer is up! - Unsecured: http://localhost:%1$d - Secured: https://localhost:%2$d - """, server.port(), server.port("secured")); - } - - static void setup(WebServerConfig.Builder server, Config config) { - server.config(config) - .routing(ServerConfigMain::plainRouting) - .putSocket("secured", socket -> socket - .from(server.sockets().get("secured")) - .routing(routing -> routing - .register("/", new SecureService()))); - } - - private static void plainRouting(HttpRouting.Builder routing) { - routing.get("/", (req, res) -> res.send("Hello world unsecured!")); - } -} diff --git a/examples/webserver/mutual-tls/src/main/java/io/helidon/examples/webserver/mtls/package-info.java b/examples/webserver/mutual-tls/src/main/java/io/helidon/examples/webserver/mtls/package-info.java deleted file mode 100644 index 8ccbb50a402..00000000000 --- a/examples/webserver/mutual-tls/src/main/java/io/helidon/examples/webserver/mtls/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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 of mutual TLS configuration for {@link io.helidon.webserver.WebServer} and {@link io.helidon.webclient.WebClient}, - * using both {@link io.helidon.config.Config} and builder based approach. - */ -package io.helidon.examples.webserver.mtls; diff --git a/examples/webserver/mutual-tls/src/main/resources/application.yaml b/examples/webserver/mutual-tls/src/main/resources/application.yaml deleted file mode 100644 index 959a9d9b01a..00000000000 --- a/examples/webserver/mutual-tls/src/main/resources/application.yaml +++ /dev/null @@ -1,50 +0,0 @@ -# -# Copyright (c) 2020, 2024 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 - sockets: - - name: "secured" - port: 443 - tls: - endpoint-identification-algorithm: "NONE" - client-auth: "REQUIRED" - trust: - keystore: - passphrase: "changeit" - trust-store: true - resource: - resource-path: "server.p12" - private-key: - keystore: - passphrase: "changeit" - resource: - resource-path: "server.p12" - -client: - tls: - client-auth: "REQUIRED" - trust: - keystore: - passphrase: "changeit" - trust-store: true - resource: - resource-path: "client.p12" - private-key: - keystore: - passphrase: "changeit" - resource: - resource-path: "client.p12" diff --git a/examples/webserver/mutual-tls/src/main/resources/client.p12 b/examples/webserver/mutual-tls/src/main/resources/client.p12 deleted file mode 100644 index 9529b6722be0cb920ecceae276fb9be270ac30ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4274 zcmY+EWmFW5mxq~Q7#eAY?vNpd98yA324A|7E&)MF34tMo?vxto5Rpc@8!73Ml929{ z^_<;(|GOXVx#vE=^Sd7(7?Su45P%6o65D}sxx-Y#t_T6x05p==0E8sg`HMARNUVbY z7h$D^~;~3<@HbrP1JF?jJs` z6^95t$Yv;EOBIy^ftCP6W8U9uIceUj$0**t;M_jK%g^r=91U&J| zA?b9c3g;p<#y36wI4T0+iqBx`y-w7s7x4h;ZdfA>T~7_N78a>>;|w_wZ$XD&w8NdJ zIRewBBgpP2yAwmJk<@Mz*27x#1?8rs%fGoF{ABwpp_+|t{g(<{_&4r+>6;H@o7AeK z2dPUpT0Mvh&Up=fnogSAPj#t&vx=TZxlAj;-B(E<%*&vD)U3&M1&K~TVaF0Zsf&?^ zVf-9t{rqyHg?iNT&PS5WuEt(nNrj=Zy=|ciUnpilyK?bvaPI7YQ8cVoa z<6{;HhahT|1Nlo&rY~Zp!ixsE|oUYQJw)sqN2~+X$Ta)7LOmHR@ zD4L<=6DRvW`S?RU33%QoRr!@og1F%yF$s`EeIGKY*7aKmY3Dlc@fkOm_pRY_S&CkY zXBVt7zBJp8HeJK-gTL8qekqE?;1-V0Ux{QRMehc8)DD`k(lSSVsF#@!13g0-))Aq1 zx!q0a=3L?gg;~o=ufw2pVG$(jH7_Zt=Zq<^=v@yCK9z9W91BFFxzG#6bHI-= zE2f<_sxi}4CPTo2B`dE|X^XcWDI&B4sfXW+%(0c;EYYS>(z@ajP|4bN-#bR@YG9vi zLLO#%;g);xuKd3NLrM5LLfV-iCovUBlXsyMJ4^0cSpHGa^L<215$lwK=o@ne5`Fdk z)f1hisi8hH`;oE)k&DJLwV{AoV-+F$t>!EOt=#JOp5pJf&WZChuT~52TD{1uS}NGt zWYz2tL~E(-)OWtU;AFHB(aTgTIbtvK$nlfT=1~Fd7nnzr-m!ypdmQ5(y0NigMxpu5 zqx;=ZaS-cd@T=GZj29Oxo$uV20w6=w*dOLJOj^$MY{SP?P;D;pCt0zFG7xip@89=Y z&7g@GsIY%3q!EAny3IM*|GR=pVGl}^xAeBLXH8$pCiAADp`OJ#%w4giW$zUbT9moP zfANE8qmq(hOW9lQGy7fz3tdVr3Bs!(WKktd$G45{(alWGvRMo782(uj9m79KfHr+B z1?R$!UnQI=$DWhDH+7 z%#Lx-f7H!|-2vsLq9+7bkrMcjd$w6Sli4urGFJx`tRv_sPEM_Hr+kZmD2(J^UE-1p zfEa)n0x;(PAPNC;5UGxXvkj8~940OxAS5OxEG8%fL*o4(PlM4&yp+Ev0SLhOyCVOs zV*_AM!Fd1cYycQW3nG80Q|&ZswREEI7QFh3)6(=7*L4txiP5bQh{V%Sj+^Cl&ZDUK zb}Fp`Ds2++j{MlE`bVQpR`ku> zp-46|+7DYG=+Z}Vu=43hem47g)Zv`Vdg83OnXN-{k9Rig=1$by zgVBqNyYESue&!>3RZVe&d5 zBJ4{EQMp@z^)WTQB~w&poo#xFnZwH$veOM&63k}<)W+#Ol;Z~0y+4a2o$EfFslU7dxi zMM|$m2g;&a!bY#UvwD3W^%o}-Vsnb2T1+IJ@|y^s<7EGr3>CpxIG^)QIJow zX|~eF@;)_Z=2>q~d`uj6jOJtHz4*-~3Aggl64PTOn`=2{sQPDr(!qAchg+56BX^IR zG}kIhU(K;{__<7nN=m>NHN><=mwZ|&#ElLz$ms8fo5m~I4-eyA?YfmKd1WC_yHZyB z1>ajL(EWN$hWt#Gf^Ln7sXyG4bn7*aMjdmv(0(N%;%9Cz35UnLT;}FDpSPLq$8#KH zfO?&SR?ulVb!e)c;`2170}_Rf;f+Ff{l2d!ypk;MD?~{z%`olCY~MN#%j#xk3&#HA z4UL*~OUm(HFxsj3l_t?#fOfdN+Nv0uKtOzFcBX#X-n+Q|5qwswDReL+1lqI6eqI+s zA>iso}dqWd-bd7Qtb z8}fb-hrIbyNvhl6S7JMj;W!AjJpE?mzI=^f>NRRhL%GlrR`FB(U;F`3S!&w z*bN))--wM-!jv{LGc5X^XYf$OAm$w-ZRIlmcuJ6ony#-|fX+11i#HiNgJd$?^gdLk z;8k&Y4pWR{*RPPg9x*a`o&boLh&_?*-k+Jp;+C(-3lzmi`WkvL6AyXv5&lB`%XN@auD^PMzqdjQmqAzF`+ELClv7 z+t`*OeeY8e7C07W2OGo3TS!X>$I?s$C2uis)*Gc|hfTT61jpZKIC$oMb516z9(7y9 zqmlyg8|M8Evj41Y53x6|Jd3~l(eqm{+g6~9Nu}vvpWs*04f!OhE?UF8 zP$raAZ93H6@=Q{2rNFGpu*A5U(thENMyg?uUOdo?X*<$_hS2S!@DzO(cj^oM&%J}Q zk9hXA*#GdvK?C8LeHva@$}%isqrQw|O>w&YuiX53(8Zi=eS-dv0@t{mJBE?WC%knF zbtA7GUW=@;O5Z&pl4`h*PivVWF}i8i$nTFQxkEN+4Hz`Ea$Y9Jd3TAR`+phWHdB3@ zHlnZ%ZgHw@ik;+E{;ASZ)rE#lH%HCQX1#3PexWeB9b=ZiPp%IJ&4o&!w?ci=dM3%V z-xqdE@~6&h*cS{f{+Nk(g%!OAaFm5+9B;)tC9W4cA}59{JkaD{7l0a#_nG2T2PV!X zH827zB{rr52#sKUfpMZEannsR)K*t{mM0?i;bd8)j7`>|o$Vj2(S3}${MA6!pq3=m zSCbRLM?_@_7tdwr%el;Rf(J7bdp7c=))wzI@24I=e9&detP&1PEQ206S|o}m+CI`~ z#a)qRnd-5rHjsOQ;lY~Cvtx1nnt905>o$S!%8DZx7Obatt+ zltN6&?B?0z^iTrxFeGaTXtx~IoY zQhh1-?YN^63wmFeS=@d5f;Wf(jX*ji$h$S@~C#u^OCRt0dNzSj)Ssr02Uw zTMShL2Aq??u!xIgEG-2}%rD-4;@~3plf~q19n!QDQByqFGZ-@r7mNiZ!UWP_VSvcr ySMN1EP!kzPqlH$iDSg@zVbj4Naw{wM3UjPL;QW#Nk32ga}G^%1B|3 z$y!T;T6h;(oz2NqfEeJ2(7E)I;=X*zWi@q6&Q2wST?tqg^+{`WMXjHN6^&<3kn zS?w;8$N&7Ga$`!~hRN}+(0h&e;9n)0g%9geZ1lWA`IPr2NI=ZtdWQnS~w=d(QdRPq0`OGT~ zs-=h7eR-qop)?PJ@L9jNE-oegXKjY_CcrZM6% zwE1cttnwD_Fs0C4El1}Ux>?>-AoWn9J2V$NR{n&V&t7A@k9m4)*&GjN2gKEU;aCEFZL% zclT(`+i>ZW;U4vYtb%1S*|iiZ-7fjDLXjEY42K79`aso&YACM=a@ z3cjU2MGof=uL%Svq?MX~(5oLGdf?SYPPo#0#cSdWfUr)$?&SOC(NlfvN&D!Y5kkJo zc}Pj;`8U=f%=DuqU?!t!OJyCV~_l+ut*x?Jq-4xj3GA>6$wt zvtBap?ZgUoI~oMe%kz(a$4lT9o1+(d99*B;wR^ufl6(4wQRFeRU{>)6OHru4IwZpiGC^ce6dk$e-zY)2v}%E8kcg zo=W6i6)q7v%i4Li>xY|&tcsvdMcb!8VfkV=vKy}5A5d5+IBlqNIQ#1uZE<0pgT5UC zJto}7$s#SlV4mOM!CP-$8a2WW1$c_drlE=&=?Y(TrfTDJE)6)%i_2*5^VwBFK z775#npEXVe`%!lN0D|vyGn77`~Jbqc{6Tu%2>&F(MP zrgjHCzsE_wJd_%L{+rb2D5#@J2QJ3PV5Gz*)SqiKB=0h+^0X6i76 zrk!HhZn4K(;8IfUmisa(j zA^B`47y!ups>72zBsd0cy;)p%P{9CodVReh5NGHvsZ2jA(YEJ_%Z#cE3=&Iyn`cd2iWLi7Da6eQI5ssTSN)iG5V_8##~7NpEOW5nIF9x_Vq>ut z+JOy0N~pkARLEsl)|?1SEmmRs&Db1zxb*+cFY$+ zBd&qB93k%_rqLT_t*8X^a)pH3wKzIr2t3??)Bra4`Qu2*+=5;ZdgA+A&&_&`uLJ*SID&9fk+cNw=Z+a399&z54l_eK(D6U*#T0J7(wM3R^UE|CJ zA)UQY&b8bPv_Gb-2uu?N#neX&8ijebfe-)MomcOR+en+!a8*nsOyn z9a*Vu;LY&kYOIf(cW{W@gzBQ}^38+EtEG1{s&$(UfcrY-p`SOAKW#D?+iw55))hwr zs#44XkLk+DWqy*6b{v*2wcswrX7x?;Fb<*J4y;b3&l{gR<9+nXXQ(#_zRL z5`W^vmgJ78()I1OiP;}J8-yp-`}xUqho$*ANy5DA<+G3by@+{8^{d^91RVX#cXU^}dnoklyS2}gFQ7`uQUK&lFjPLhHW_L1})-*wqN9H}VKteUeof_}e z)&OI|blsjNzM4xq%=JKNmWF6xMy%TCAn!37*})Oe;k3Kad4cF#S;Js8Es|AwZJlY% zw~Gsx&Ptv6V`R`>=L8>Vfu#2?`m9m^^=fAzu8Q5ZDMiIOSyBJpixqs5@-3gt+3zuV z^cvY7IPaiIGTJQJsPwlf5^oICI~?I)n-b1fx(mwBt|QXPzcgupMZTnM-NJ(IHVykP z{a%DxZ=_P^Cic)7{rqZKr)|329BMNG!1m8Aw=irrX!henm%L(??q|5w0sd_>(S9d1p*RDWv$07{K`Dqdq%*}_ql`C z28;NcUJh3xS)j1s@M2i%Fm2UC!YgV%!T`zllmkqNq6ata{RAq5K}w|XT_UBLGb8+; z8>1Ren}b@^aPrR zW%MB9);qHl!Ly;CwpL^ILfF$u*nG+0sc9;44lP#ZQ{E{rQ=nu0B-uP6VPUUOY_H{F zCARtftnosVIGg)P5VNmD9YAx_;K`%BUxPg;V zPJPim^CEr2yCCtV-Hb~qeCqp3S}l)jHl5fWH~}o-P!q{*Q&g^c*0M&JrYC$ybQ3X~g|pp!T8(+5V_n|2K_In1n!n77n@dRFeurg@8!t_@meD2j1UyQ% z86z?!MG5jpDGju@eu^2Q@_YaR9m~v?{%0uuaB6^%&=P5}7~t}yK6^{Hf?uPwK5I;W zsJc0j!ByaT>kwn-wMr$`#iwH;(LL?m@#}4VT8XIHvZPp^0PPq(b;#uNf*Y&NbMHX; zky*436Z?{I7vwXV)qwYjbfl@LiQrJ)QY>MTd4q6 zPY-Yl1zHm&KdU0z?a!^g`aQ~i8uwCY2kZ&qHqxeYS0)k7Y-Si!(*9>TRAMa#Ldb#Hyu!>PvTYH^XY6IQz~I}b+cx%1rO&*u&d5|nROdQ?Qp zWV0~ti>fq+Tru(FNOER`A z?Vn^+UZy~glabV8C@(h(4Wd^~OG#JDU#t|!1q!Rsb9`_%!qja> zZj=Xdy!etVRjPsmK)W+Ig2dF)818*yU?8^5GiXklq^_n&G4r1zEt5oW3s#**Jau^E!_>aFfIm^ekt= z-R1mn)KFP9Ech&a*pO1CxzgF0({%2`v-n@+vL0i_%({@l)eLi6cp9OQP$J8Zet+?> zm5%$kPOf4`@e1f-kt`K20k~7knC4f$-z96_i^Y&q_V+BLgACBmivAe*rU}-vj^v diff --git a/examples/webserver/mutual-tls/src/test/java/io/helidon/examples/webserver/mtls/MutualTlsExampleBuilderTest.java b/examples/webserver/mutual-tls/src/test/java/io/helidon/examples/webserver/mtls/MutualTlsExampleBuilderTest.java deleted file mode 100644 index a6e8c1d64a1..00000000000 --- a/examples/webserver/mutual-tls/src/test/java/io/helidon/examples/webserver/mtls/MutualTlsExampleBuilderTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2020, 2024 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.webserver.mtls; - -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; - -import org.hamcrest.MatcherAssert; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; - -/** - * Test of mutual TLS example. - */ -@ServerTest -public class MutualTlsExampleBuilderTest { - - private final WebServer server; - - public MutualTlsExampleBuilderTest(WebServer server) { - this.server = server; - } - - @SetUpServer - static void setup(WebServerConfig.Builder server) { - server.port(0); - server.putSocket("secured", it -> it - .from(server.sockets().get("secured")) - .port(0)); - ServerBuilderMain.setup(server); - } - - @Test - public void testBuilderAccessSuccessful() { - Http1Client client = ClientBuilderMain.createClient(); - MatcherAssert.assertThat(ClientBuilderMain.callUnsecured(client, server.port()), is("Hello world unsecured!")); - MatcherAssert.assertThat(ClientBuilderMain.callSecured(client, server.port("secured")), is("Hello Helidon-client!")); - } -} diff --git a/examples/webserver/mutual-tls/src/test/java/io/helidon/examples/webserver/mtls/MutualTlsExampleConfigTest.java b/examples/webserver/mutual-tls/src/test/java/io/helidon/examples/webserver/mtls/MutualTlsExampleConfigTest.java deleted file mode 100644 index 734f25177e6..00000000000 --- a/examples/webserver/mutual-tls/src/test/java/io/helidon/examples/webserver/mtls/MutualTlsExampleConfigTest.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2020, 2024 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.webserver.mtls; - -import java.util.Map; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.config.OverrideSources; -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; - -import org.junit.jupiter.api.Test; - -import static io.helidon.examples.webserver.mtls.ClientConfigMain.callSecured; -import static io.helidon.examples.webserver.mtls.ClientConfigMain.callUnsecured; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Test of mutual TLS example. - */ -@ServerTest -public class MutualTlsExampleConfigTest { - - private static Config config; - private final WebServer server; - private final Http1Client client; - - public MutualTlsExampleConfigTest(WebServer server) { - this.server = server; - this.client = Http1Client.builder().config(config.get("client")).build(); - } - - @SetUpServer - static void setup(WebServerConfig.Builder server) { - config = Config.builder() - .sources(ConfigSources.classpath("application.yaml")) - .overrides(() -> OverrideSources.create(Map.of( - "server.port", "0", - "server.sockets.*.port", "0" - ))) - .build(); - ServerConfigMain.setup(server, config.get("server")); - } - - @Test - public void testConfigAccessSuccessful() { - assertThat(callUnsecured(client, server.port()), is("Hello world unsecured!")); - assertThat(callSecured(client, server.port("secured")), is("Hello Helidon-client!")); - } -} \ No newline at end of file diff --git a/examples/webserver/observe/pom.xml b/examples/webserver/observe/pom.xml deleted file mode 100644 index 23e8e8f78ab..00000000000 --- a/examples/webserver/observe/pom.xml +++ /dev/null @@ -1,115 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - - io.helidon.examples.webserver - helidon-examples-webserver-observe - Helidon Examples WebServer Observe - - - io.helidon.examples.webserver.observe.ObserveMain - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver.observe - helidon-webserver-observe-health - - - io.helidon.webserver.observe - helidon-webserver-observe-config - - - io.helidon.webserver.observe - helidon-webserver-observe-info - - - io.helidon.webserver.observe - helidon-webserver-observe-log - - - io.helidon.webserver - helidon-webserver-security - - - io.helidon.security.providers - helidon-security-providers-http-auth - - - io.helidon.webserver - helidon-webserver-context - - - io.helidon.config - helidon-config-yaml - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.apache.maven.plugins - maven-failsafe-plugin - - - - integration-test - verify - - - - - - - diff --git a/examples/webserver/observe/src/main/java/io/helidon/examples/webserver/observe/ObserveMain.java b/examples/webserver/observe/src/main/java/io/helidon/examples/webserver/observe/ObserveMain.java deleted file mode 100644 index 14b6250b19d..00000000000 --- a/examples/webserver/observe/src/main/java/io/helidon/examples/webserver/observe/ObserveMain.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.webserver.observe; - -import io.helidon.config.Config; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.http.HttpRouting; - -/** - * Register observe support with all available observers and NO security. - * Some observers may disclose secret or private information and should be protected, use with care (and security). - */ -public class ObserveMain { - private ObserveMain() { - } - - /** - * Main method. - * - * @param args ignored - */ - public static void main(String[] args) { - // load logging - LogConfig.configureRuntime(); - - Config config = Config.create(); - - WebServer server = WebServer.builder() - .config(config.get("server")) - .routing(ObserveMain::routing) - .build() - .start(); - - System.out.println("WEB server is up! http://localhost:" + server.port()); - } - - /** - * Set up HTTP routing. - * This method is used from tests as well. - * - * @param router HTTP routing builder - */ - static void routing(HttpRouting.Builder router) { - router.get("/", (req, res) -> res.send("WebServer Works!")); - } -} diff --git a/examples/webserver/observe/src/main/java/io/helidon/examples/webserver/observe/package-info.java b/examples/webserver/observe/src/main/java/io/helidon/examples/webserver/observe/package-info.java deleted file mode 100644 index a61404f2564..00000000000 --- a/examples/webserver/observe/src/main/java/io/helidon/examples/webserver/observe/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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. - */ - -/** - * Observability example. - */ -package io.helidon.examples.webserver.observe; diff --git a/examples/webserver/observe/src/main/resources/application.yaml b/examples/webserver/observe/src/main/resources/application.yaml deleted file mode 100644 index 32fcd606c3a..00000000000 --- a/examples/webserver/observe/src/main/resources/application.yaml +++ /dev/null @@ -1,44 +0,0 @@ -# -# Copyright (c) 2022, 2024 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: - host: "127.0.0.1" - port: 8080 - features: - security: - paths: - - path: "/observe/log/*" - authenticate: true - - path: "/observe/config/*" - authenticate: true - observe: - observers: - info: - values: - name: "Observe Example" - version: "1.0.0" - -security: - providers: - - http-basic-auth: - users: - - login: "admin" - password: "changeit" - roles: ["observe"] -app: - greeting: "Hello!" - app-secret: "Do not print this in observe" - app-password: "Do not print this in observe" diff --git a/examples/webserver/observe/src/main/resources/logging.properties b/examples/webserver/observe/src/main/resources/logging.properties deleted file mode 100644 index 1c99b019810..00000000000 --- a/examples/webserver/observe/src/main/resources/logging.properties +++ /dev/null @@ -1,24 +0,0 @@ -# -# Copyright (c) 2022, 2023 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. -# -handlers=java.util.logging.ConsoleHandler -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS.%1$tL %5$s%6$s%n -# Global logging level. Can be overridden by specific loggers -.level=INFO -io.helidon.webserve.level=INFO - -java.util.logging.ConsoleHandler.level=ALL -# to enable security audit logging for Helidon: -# AUDIT.level=FINEST diff --git a/examples/webserver/observe/src/test/java/io/helidon/examples/webserver/observe/AbstractObserveTest.java b/examples/webserver/observe/src/test/java/io/helidon/examples/webserver/observe/AbstractObserveTest.java deleted file mode 100644 index 37a80b3caf6..00000000000 --- a/examples/webserver/observe/src/test/java/io/helidon/examples/webserver/observe/AbstractObserveTest.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.webserver.observe; - -import io.helidon.http.Status; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.http.HttpRouting; -import io.helidon.webserver.testing.junit5.SetUpRoute; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -abstract class AbstractObserveTest { - private final Http1Client client; - - protected AbstractObserveTest(Http1Client client) { - this.client = client; - } - - @SetUpRoute - static void routing(HttpRouting.Builder builder) { - ObserveMain.routing(builder); - } - - @Test - void testRootRoute() { - String response = client.get("/") - .request() - .as(String.class); - - assertThat(response, is("WebServer Works!")); - } - - @Test - void testConfigObserver() { - try (Http1ClientResponse response = client.get("/observe/config/profile").request()) { - // this requires basic authentication - assertThat(response.status(), is(Status.UNAUTHORIZED_401)); - } - } - - @Test - void testHealthObserver() { - try (Http1ClientResponse response = client.get("/observe/health").request()) { - assertThat(response.status(), is(Status.NO_CONTENT_204)); - } - } - - @Test - void testInfoObserver() { - try (Http1ClientResponse response = client.get("/observe/info").request()) { - assertThat(response.status(), is(Status.OK_200)); - } - } -} diff --git a/examples/webserver/observe/src/test/java/io/helidon/examples/webserver/observe/ObserveRoutingIT.java b/examples/webserver/observe/src/test/java/io/helidon/examples/webserver/observe/ObserveRoutingIT.java deleted file mode 100644 index 786d123fb25..00000000000 --- a/examples/webserver/observe/src/test/java/io/helidon/examples/webserver/observe/ObserveRoutingIT.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.webserver.observe; - -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webclient.http1.Http1Client; - -@ServerTest -class ObserveRoutingIT extends AbstractObserveTest { - ObserveRoutingIT(Http1Client client) { - super(client); - } -} diff --git a/examples/webserver/observe/src/test/java/io/helidon/examples/webserver/observe/ObserveRoutingTest.java b/examples/webserver/observe/src/test/java/io/helidon/examples/webserver/observe/ObserveRoutingTest.java deleted file mode 100644 index f7ff90614e2..00000000000 --- a/examples/webserver/observe/src/test/java/io/helidon/examples/webserver/observe/ObserveRoutingTest.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.webserver.observe; - -import io.helidon.webserver.testing.junit5.DirectClient; -import io.helidon.webserver.testing.junit5.RoutingTest; - -@RoutingTest -class ObserveRoutingTest extends AbstractObserveTest { - ObserveRoutingTest(DirectClient client) { - super(client); - } -} - diff --git a/examples/webserver/observe/src/test/resources/logging-test.properties b/examples/webserver/observe/src/test/resources/logging-test.properties deleted file mode 100644 index e0e9004a51a..00000000000 --- a/examples/webserver/observe/src/test/resources/logging-test.properties +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) 2022, 2023 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. -# -handlers=java.util.logging.ConsoleHandler -java.util.logging.ConsoleHandler.level=FINEST -java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter -# java.util.logging.SimpleFormatter.format = [%1$tc] %5$s %6$s%n -java.util.logging.SimpleFormatter.format=%1$tH:%1$tM:%1$tS %5$s%6$s%n -# Global logging level. Can be overridden by specific loggers -.level=WARNING diff --git a/examples/webserver/opentracing/Dockerfile b/examples/webserver/opentracing/Dockerfile deleted file mode 100644 index 6a08ba21e88..00000000000 --- a/examples/webserver/opentracing/Dockerfile +++ /dev/null @@ -1,56 +0,0 @@ -# -# Copyright (c) 2018, 2024 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. -# - -# 1st stage, build the app -FROM container-registry.oracle.com/java/jdk-no-fee-term:21 as build - -# Install maven -WORKDIR /usr/share -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 -Dmaven.test.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 container-registry.oracle.com/java/jdk-no-fee-term:21 -WORKDIR /helidon - -# Copy the binary built in the 1st stage -COPY --from=build /helidon/target/helidon-examples-webserver-opentracing.jar ./ -COPY --from=build /helidon/target/libs ./libs - -ENV tracing.host="zipkin" - -CMD ["java", "-jar", "helidon-examples-webserver-opentracing.jar"] - -EXPOSE 8080 diff --git a/examples/webserver/opentracing/README.md b/examples/webserver/opentracing/README.md deleted file mode 100644 index 71f761b9a65..00000000000 --- a/examples/webserver/opentracing/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# Opentracing Example Application - -## Start Zipkin - -With Docker: -```shell -docker run --name zipkin -d -p 9411:9411 openzipkin/zipkin -``` - -With Java 8+: -```shell -curl -sSL https://zipkin.io/quickstart.sh | bash -s -java -jar zipkin.jar -``` - -## Build and run - -With Docker: -```shell -docker build -t helidon-webserver-opentracing-example . -docker run --rm -d --link zipkin --name helidon-webserver-opentracing-example \ - -p 8080:8080 helidon-webserver-opentracing-example:latest -``` - -With Java 8+: -```shell -mvn package -java -jar target/helidon-examples-webserver-opentracing.jar -``` - -Try the endpoint: -```shell -curl http://localhost:8080/test -``` - -Then check out the traces at http://localhost:9411. - -Stop the docker containers: -```shell -docker stop zipkin helidon-webserver-opentracing-example -``` diff --git a/examples/webserver/opentracing/pom.xml b/examples/webserver/opentracing/pom.xml deleted file mode 100644 index 5d2130acce3..00000000000 --- a/examples/webserver/opentracing/pom.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.webserver - helidon-examples-webserver-opentracing - Helidon Examples WebServer OpenTracing - - - An example app with Open Tracing support. - - - - io.helidon.examples.webserver.opentracing.Main - 2.23.4 - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver.observe - helidon-webserver-observe-tracing - - - io.helidon.logging - helidon-logging-common - - - io.helidon.config - helidon-config - - - io.helidon.tracing.providers - helidon-tracing-providers-zipkin - - - io.helidon.logging - helidon-logging-jul - runtime - - - org.testcontainers - junit-jupiter - test - - - org.junit.jupiter - junit-jupiter-api - test - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - io.helidon.webclient - helidon-webclient - test - - - org.hamcrest - hamcrest-all - test - - - jakarta.json - jakarta.json-api - test - - - io.helidon.common.testing - helidon-common-testing-junit5 - test - - - io.helidon.http.media - helidon-http-media-jsonp - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/webserver/opentracing/src/main/java/io/helidon/examples/webserver/opentracing/Main.java b/examples/webserver/opentracing/src/main/java/io/helidon/examples/webserver/opentracing/Main.java deleted file mode 100644 index 3282b3b7612..00000000000 --- a/examples/webserver/opentracing/src/main/java/io/helidon/examples/webserver/opentracing/Main.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2017, 2024 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.webserver.opentracing; - -import java.util.Map; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.logging.common.LogConfig; -import io.helidon.tracing.Tracer; -import io.helidon.tracing.TracerBuilder; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.observe.ObserveFeature; -import io.helidon.webserver.observe.tracing.TracingObserver; - -/** - * The application uses Open Tracing and sends the collected data to ZipKin. - * - * @see io.helidon.tracing.TracerBuilder - * @see io.helidon.tracing.providers.zipkin.ZipkinTracerBuilder - */ -public final class Main { - - private Main() { - } - - /** - * Run the OpenTracing application. - * - * @param args not used - */ - public static void main(String[] args) { - - // configure logging in order to not have the standard JVM defaults - LogConfig.configureRuntime(); - - WebServer server = setupServer(WebServerConfig.builder(), 9411); - - System.out.println("Started at http://localhost:" + server.port()); - } - - static WebServer setupServer(WebServerConfig.Builder builder, int port) { - Config config = Config.builder() - .sources(ConfigSources.create(Map.of("host", "localhost", - "port", "8080"))) - .build(); - - Tracer tracer = TracerBuilder.create("demo-first") - .collectorPort(port) - .registerGlobal(true) - .build(); - - return builder - .config(config) - .addFeature(ObserveFeature.builder() - .addObserver(TracingObserver.create(tracer)) - .build()) - .routing(routing -> routing - .get("/test", (req, res) -> res.send("Hello World!")) - .post("/hello", (req, res) -> res.send("Hello: " + req.content().as(String.class)))) - .build() - .start(); - } -} diff --git a/examples/webserver/opentracing/src/main/java/io/helidon/examples/webserver/opentracing/package-info.java b/examples/webserver/opentracing/src/main/java/io/helidon/examples/webserver/opentracing/package-info.java deleted file mode 100644 index 33bdba7930d..00000000000 --- a/examples/webserver/opentracing/src/main/java/io/helidon/examples/webserver/opentracing/package-info.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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. - */ - -/** - * An example of WebServer app supporting Open Tracing. - * - * @see io.helidon.examples.webserver.opentracing.Main - */ -package io.helidon.examples.webserver.opentracing; diff --git a/examples/webserver/opentracing/src/main/resources/logging.properties b/examples/webserver/opentracing/src/main/resources/logging.properties deleted file mode 100644 index 673d47dd82d..00000000000 --- a/examples/webserver/opentracing/src/main/resources/logging.properties +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2017, 2023 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. -# - - -#All attributes details -handlers=io.helidon.logging.jul.HelidonConsoleHandler -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 - -#All log level details -.level=FINEST - -io.helidon.webserver.level=FINEST -org.glassfish.jersey.internal.Errors.level=SEVERE diff --git a/examples/webserver/opentracing/src/test/java/io/helidon/examples/webserver/opentracing/MainTest.java b/examples/webserver/opentracing/src/test/java/io/helidon/examples/webserver/opentracing/MainTest.java deleted file mode 100644 index 9079fd48cc2..00000000000 --- a/examples/webserver/opentracing/src/test/java/io/helidon/examples/webserver/opentracing/MainTest.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2024 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.webserver.opentracing; - -import io.helidon.http.Status; -import io.helidon.http.media.jsonp.JsonpSupport; -import io.helidon.webclient.api.HttpClientResponse; -import io.helidon.webclient.api.WebClient; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.WebServer; - -import jakarta.json.JsonArray; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.testcontainers.containers.GenericContainer; -import org.testcontainers.containers.wait.strategy.Wait; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; - -import static io.helidon.common.testing.junit5.MatcherWithRetry.assertThatWithRetry; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -@Testcontainers(disabledWithoutDocker = true) -public class MainTest { - private static WebClient client; - private static WebServer server; - private static Http1Client zipkinClient; - - @Container - private static final GenericContainer container = new GenericContainer<>("openzipkin/zipkin") - .withExposedPorts(9411) - .waitingFor(Wait.forHttp("/health").forPort(9411)); - - @BeforeAll - static void checkContainer() { - server = Main.setupServer(WebServer.builder(), container.getMappedPort(9411)); - client = WebClient.create(config -> config.baseUri("http://localhost:" + server.port()) - .addMediaSupport(JsonpSupport.create())); - zipkinClient = Http1Client.create(config -> config - .baseUri("http://localhost:" + container.getMappedPort(9411))); - } - - @AfterAll - static void close() { - if (server != null) { - server.stop(); - } - } - - @Test - void test() { - try (Http1ClientResponse response = zipkinClient.get("/zipkin/api/v2/traces").request()) { - JsonArray array = response.as(JsonArray.class); - assertThat(response.status(), is(Status.OK_200)); - assertThat(array.isEmpty(), is(true)); - } - - try (HttpClientResponse response = client.get("test").request()) { - assertThat(response.status(), is(Status.OK_200)); - assertThat(response.as(String.class), is("Hello World!")); - } - - assertThatWithRetry("Traces must contains service name", - MainTest::getZipkinTraces, containsString("demo-first")); - assertThatWithRetry("Traces must contains pinged endpoint", - MainTest::getZipkinTraces, containsString(client.get("test").uri().toString())); - } - - private static String getZipkinTraces() { - try (Http1ClientResponse response = zipkinClient.get("/zipkin/api/v2/traces").request()) { - assertThat(response.status(), is(Status.OK_200)); - return response.as(String.class); - } - } -} diff --git a/examples/webserver/pom.xml b/examples/webserver/pom.xml deleted file mode 100644 index 0fc5cdfdc11..00000000000 --- a/examples/webserver/pom.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - 4.0.0 - - io.helidon.examples - helidon-examples-project - 4.1.0-SNAPSHOT - - io.helidon.examples.webserver - helidon-examples-webserver-project - Helidon Examples WebServer - pom - - - basic - basics - comment-aas - echo - fault-tolerance - imperative - multiport - mutual-tls - observe - opentracing - protocols - static-content - streaming - tls - tracing - tutorial - websocket - - diff --git a/examples/webserver/protocols/pom.xml b/examples/webserver/protocols/pom.xml deleted file mode 100644 index 50633319a0e..00000000000 --- a/examples/webserver/protocols/pom.xml +++ /dev/null @@ -1,114 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - - io.helidon.examples.webserver - helidon-examples-webserver-protocols - Helidon Examples WebServer Protocols - - - io.helidon.examples.webserver.protocols.ProtocolsMain - - - - - - javax.annotation - javax.annotation-api - 1.3.2 - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver - helidon-webserver-grpc - - - io.helidon.webclient - helidon-webclient-http2 - - - io.helidon.webserver - helidon-webserver-websocket - - - io.helidon.webserver - helidon-webserver-http2 - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - kr.motd.maven - os-maven-plugin - ${version.plugin.os} - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.xolstice.maven.plugins - protobuf-maven-plugin - 0.6.1 - - - - compile - compile-custom - - - - - com.google.protobuf:protoc:${version.lib.google-protobuf}:exe:${os.detected.classifier} - grpc-java - io.grpc:protoc-gen-grpc-java:${version.lib.grpc}:exe:${os.detected.classifier} - - - - - - diff --git a/examples/webserver/protocols/src/main/java/io/helidon/examples/webserver/protocols/ProtocolsMain.java b/examples/webserver/protocols/src/main/java/io/helidon/examples/webserver/protocols/ProtocolsMain.java deleted file mode 100644 index 6f4db9453aa..00000000000 --- a/examples/webserver/protocols/src/main/java/io/helidon/examples/webserver/protocols/ProtocolsMain.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2022, 2024 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.webserver.protocols; - -import java.nio.charset.StandardCharsets; -import java.util.Locale; - -import io.helidon.common.configurable.Resource; -import io.helidon.common.pki.Keys; -import io.helidon.common.tls.Tls; -import io.helidon.examples.grpc.strings.Strings; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.grpc.GrpcRouting; -import io.helidon.webserver.http1.Http1Route; -import io.helidon.webserver.http2.Http2Route; -import io.helidon.webserver.websocket.WsRouting; -import io.helidon.websocket.WsListener; -import io.helidon.websocket.WsSession; - -import io.grpc.stub.StreamObserver; - -import static io.helidon.grpc.core.ResponseHelper.complete; -import static io.helidon.http.Method.GET; - -/** - * Example showing supported protocols. - */ -public class ProtocolsMain { - private static final byte[] RESPONSE = "Hello from WebServer!".getBytes(StandardCharsets.UTF_8); - - private ProtocolsMain() { - } - - /** - * Main method. - * - * @param args ignored - */ - public static void main(String[] args) { - LogConfig.configureRuntime(); - - Keys privateKeyConfig = privateKey(); - - Tls tls = Tls.builder() - .privateKey(privateKeyConfig.privateKey().get()) - .privateKeyCertChain(privateKeyConfig.certChain()) - .build(); - - WebServer.builder() - .port(8080) - .host("127.0.0.1") - .putSocket("https", - builder -> builder.port(8081) - .host("127.0.0.1") - .tls(tls) - .receiveBufferSize(4096) - .backlog(8192) - ) - .routing(router -> router - .get("/", (req, res) -> res.send(RESPONSE)) - .route(Http1Route.route(GET, "/versionspecific", (req, res) -> res.send("HTTP/1.1 route"))) - .route(Http2Route.route(GET, "/versionspecific", (req, res) -> res.send("HTTP/2 route")))) - .addRouting(GrpcRouting.builder() - .unary(Strings.getDescriptor(), - "StringService", - "Upper", - ProtocolsMain::grpcUpper)) - .addRouting(WsRouting.builder() - .endpoint("/tyrus/echo", ProtocolsMain::wsEcho)) - .build() - .start(); - } - - private static void grpcUpper(Strings.StringMessage request, StreamObserver observer) { - String requestText = request.getText(); - System.out.println("grpc request: " + requestText); - complete(observer, Strings.StringMessage.newBuilder() - .setText(requestText.toUpperCase(Locale.ROOT)) - .build()); - } - - private static WsListener wsEcho() { - return new WsListener() { - @Override - public void onMessage(WsSession session, String text, boolean last) { - session.send(text, last); - System.out.println("websocket request " + text); - } - - @Override - public void onClose(WsSession session, int status, String reason) { - System.out.println("websocket closed (" + status + " " + reason + ")"); - } - }; - } - - private static Keys privateKey() { - String password = "helidon"; - - return Keys.builder() - .keystore(keystore -> keystore - .keystore(Resource.create("certificate.p12")) - .passphrase(password)) - .build(); - } -} diff --git a/examples/webserver/protocols/src/main/java/io/helidon/examples/webserver/protocols/package-info.java b/examples/webserver/protocols/src/main/java/io/helidon/examples/webserver/protocols/package-info.java deleted file mode 100644 index 466940aae3a..00000000000 --- a/examples/webserver/protocols/src/main/java/io/helidon/examples/webserver/protocols/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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. - */ - -/** - * Various supported protocols example. - */ -package io.helidon.examples.webserver.protocols; diff --git a/examples/webserver/protocols/src/main/proto/events.proto b/examples/webserver/protocols/src/main/proto/events.proto deleted file mode 100644 index 7605150f7bc..00000000000 --- a/examples/webserver/protocols/src/main/proto/events.proto +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2023 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. - */ - - -syntax = "proto3"; -option java_package = "io.helidon.webserver.grpc.events"; - -import "google/protobuf/empty.proto"; - -service EventService { - rpc Send (Message) returns (google.protobuf.Empty) {} - rpc Events (stream EventRequest) returns (stream EventResponse) {} -} - -message Message { - string text = 2; -} - -message EventRequest { - int64 id = 1; - enum Action { - SUBSCRIBE = 0; - UNSUBSCRIBE = 1; - } - Action action = 2; -} - -message EventResponse { - oneof response_type { - Subscribed subscribed = 1; - Unsubscribed unsubscribed = 2; - Event event = 3; - } -} - -message Subscribed { - int64 id = 1; -} - -message Unsubscribed { - int64 id = 1; -} - -message Event { - int64 id = 1; - string text = 2; -} diff --git a/examples/webserver/protocols/src/main/proto/strings.proto b/examples/webserver/protocols/src/main/proto/strings.proto deleted file mode 100644 index d1a4f7be178..00000000000 --- a/examples/webserver/protocols/src/main/proto/strings.proto +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2021 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. - */ - - -syntax = "proto3"; -option java_package = "io.helidon.examples.grpc.strings"; - -service StringService { - rpc Upper (StringMessage) returns (StringMessage) {} - rpc Lower (StringMessage) returns (StringMessage) {} - rpc Split (StringMessage) returns (stream StringMessage) {} - rpc Join (stream StringMessage) returns (StringMessage) {} - rpc Echo (stream StringMessage) returns (stream StringMessage) {} -} - -message StringMessage { - string text = 1; -} diff --git a/examples/webserver/protocols/src/main/resources/certificate.p12 b/examples/webserver/protocols/src/main/resources/certificate.p12 deleted file mode 100644 index b2cb83427d181db6657cca1e2a70fa49bdb40724..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2557 zcmY+^XEYm(8V7JmlMo{{TD7XS(rOdCqP1$YQbmkLgBGnF^QB0TP=wG}txZtlidCDw z)Sgw;=+!}s+9TAauJ@dK?|biu=RD{9|Ic|o{@^6&J`ivQPJ*^Tpt2DL5xX1!W8EiKoCLD{yMpA9K*pyL3J732UAlia0Jso@_1_=Z0T4J0#L{lBIEeZUWB`FI zOrazYpZuRyYsv6BeHC3~j`v3#2BuL54sF9g33lb7P}vO z^L@D&e_lq+R~&%SWhKN}ToPOtb0wP*>tMq!MR%LPxC|K2vexVZw7r)tDy)%eaTb(e zymOPI@|`_zsjBfH>KrDoY|{2>*SPVb9)3${`ioIt&lD^n1>aYJX@9jkH^NI+awU6I z5}VJ{XIl=ZcR5fqD1=dIRnSa2hXA4mPHb`**VNljMuahqhyWgC(dV1W_O{Xesk6?G|Hm} z%Ymzi5}iSx=2=rL!=M>3gKhYPO`Z(?mHSQ4hN;QSTNpTQ@_TZ?aEG2+(ZXTfydo-W6D);8#bFnW=!`VB|wJ~Lq;7IJt7k3!}g=a*lC4oPuToq z&>)ev0`D1~><0p6rOuR)8)meX01i{$W%pZFO!9`EsMYX?*za9eE-fy+0R?mEbZ?^V zzFc+fAgPl9G2L#jNiKc|5(PfYLm!q8+{>?(!{wqB78A|~5{jft$eF3V$U}(5yXB*` z<%0Ke9m{xQZUtG6@h7lib5ZWupm{+>{kp+Nqc$=+`C-ga3sm7%RHDVv=7|t;mF_7cPQllGD~yp+gV@JWi%@eQ^%O^yJEK0h!-ub zGR|wLJT*gDg2F}~2LIYcd`2&YyZ`VNZd$(dWaKE!5!GN?0{?THI@7p|Bci`PWPdhQ zJW--7*qsX}fwlezk{l9P9z+6PJB?*eM+(CBA68faz*B$LPT^VlKW)zZrHx7dM`xnW zz39KR0g*sGsZ9x^4W$E^JyaaJHlxD|v*I(~%85iIo_qP~!SHk8RNFkAUW<41n}+0r z#G78z*XPpj9C=;rI>Jg@J^Ojv#XJk}`0<_l6|}towM8=4Da!sjMYma}Q%f@;W=XKNb}azh zM@r2j*j32(O*x3HOxA=&L zYqyUN0s=%oMLLL=24t=}e@ypZ9?=*>sW<~`b4gMs$_mZU1BI?mZ;j$M!X5dGc$G&_ z%TlAZAq3I+6)Tx&m_mC`6b>b^*b%I|z5nK#!x z4=+8DC9#xuoyD7=UfF_f2dSUY69uw{LG3@ojC#@hRpxBNYLm2j=%5+-GB>9DT5-mo zlGWbm?0JQ#H|clJi^+Vk(uco~=mDF>G7TyGa@Q zwbh%8M?s6PG?>J{ot?-rkbBPMa9aW1@caj=?))-nN2G42~VPe?;x^u`J>Z__NtPR;PKNmTxJRZsRjHmS_HQgytm6aEgg`HWhYDmA#*m6f-}X9eY7|M|2=H|)_IgcA0W-c$R{g^9VCk`@mH{y$X547S z!rUXh(4yZNfl5o1iCga@P#q`H-ymx~c19ICpiQ>;g%+##uN9o0i|B&NxZTSg@o#1J z%F=B#*OwHWkJs;-UTYZl6(ouzu5m@wHIAB7{}qHrh#dh@-oPiJ!{8N_1W OY0p~c!p8BJlK%o#WVn_9 diff --git a/examples/webserver/protocols/src/main/resources/logging.properties b/examples/webserver/protocols/src/main/resources/logging.properties deleted file mode 100644 index 161f6db0dde..00000000000 --- a/examples/webserver/protocols/src/main/resources/logging.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2022, 2024 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. -# -handlers=java.util.logging.ConsoleHandler -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS.%1$tL %5$s%6$s%n -# Global logging level. Can be overridden by specific loggers -.level=INFO -io.helidon.webserver.level=INFO diff --git a/examples/webserver/static-content/README.md b/examples/webserver/static-content/README.md deleted file mode 100644 index 45b6395a100..00000000000 --- a/examples/webserver/static-content/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Static Content Example - -This application demonstrates use of the StaticContentService to serve static files - together with a simple REST service. - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-webserver-static-content.jar -``` - -Open http://localhost:8080 in your browser. diff --git a/examples/webserver/static-content/pom.xml b/examples/webserver/static-content/pom.xml deleted file mode 100644 index 393cb342c7b..00000000000 --- a/examples/webserver/static-content/pom.xml +++ /dev/null @@ -1,86 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.webserver - helidon-examples-webserver-static-content - Helidon Examples WebServer Static Content - - - Application demonstrates combination of the static content with a simple REST API. It counts accesses and display it - on the WEB page. - - - - io.helidon.examples.webserver.staticcontent.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver - helidon-webserver-static-content - - - io.helidon.http.media - helidon-http-media-jsonp - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/webserver/static-content/src/main/java/io/helidon/examples/webserver/staticcontent/CounterService.java b/examples/webserver/static-content/src/main/java/io/helidon/examples/webserver/staticcontent/CounterService.java deleted file mode 100644 index 35a18fb2cab..00000000000 --- a/examples/webserver/static-content/src/main/java/io/helidon/examples/webserver/staticcontent/CounterService.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.webserver.staticcontent; - -import java.util.Collections; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.LongAdder; - -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; - -/** - * Counts access to the WEB service. - */ -public class CounterService implements HttpService { - - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - private final LongAdder allAccessCounter = new LongAdder(); - private final AtomicInteger apiAccessCounter = new AtomicInteger(); - - @Override - public void routing(HttpRules rules) { - rules.any(this::handleAny) - .get("/api/counter", this::handleGet); - } - - private void handleAny(ServerRequest request, ServerResponse response) { - allAccessCounter.increment(); - response.next(); - } - - private void handleGet(ServerRequest request, ServerResponse response) { - int apiAcc = apiAccessCounter.incrementAndGet(); - JsonObject result = JSON.createObjectBuilder() - .add("all", allAccessCounter.longValue()) - .add("api", apiAcc) - .build(); - response.send(result); - } -} diff --git a/examples/webserver/static-content/src/main/java/io/helidon/examples/webserver/staticcontent/Main.java b/examples/webserver/static-content/src/main/java/io/helidon/examples/webserver/staticcontent/Main.java deleted file mode 100644 index a3ba615d460..00000000000 --- a/examples/webserver/static-content/src/main/java/io/helidon/examples/webserver/staticcontent/Main.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.webserver.staticcontent; - -import io.helidon.http.Header; -import io.helidon.http.HeaderNames; -import io.helidon.http.HeaderValues; -import io.helidon.http.Status; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.http.HttpRouting; -import io.helidon.webserver.staticcontent.StaticContentService; - -/** - * The application main class. - */ -public final class Main { - private static final Header UI_REDIRECT = HeaderValues.createCached(HeaderNames.LOCATION, "/ui"); - - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * - * @param args command line arguments. - */ - public static void main(String[] args) { - // load logging configuration - LogConfig.configureRuntime(); - - WebServer server = WebServer.builder() - .port(8080) - .routing(Main::routing) - .build() - .start(); - - System.out.println("WEB server is up! http://localhost:" + server.port() + "/greet"); - } - - /** - * Updates HTTP Routing. - */ - static void routing(HttpRouting.Builder routing) { - routing.any("/", (req, res) -> { - // showing the capability to run on any path, and redirecting from root - res.status(Status.MOVED_PERMANENTLY_301); - res.headers().set(UI_REDIRECT); - res.send(); - }) - .register("/ui", CounterService::new) - .register("/ui", StaticContentService.builder("WEB") - .welcomeFileName("index.html") - .build()); - } -} diff --git a/examples/webserver/static-content/src/main/java/io/helidon/examples/webserver/staticcontent/package-info.java b/examples/webserver/static-content/src/main/java/io/helidon/examples/webserver/staticcontent/package-info.java deleted file mode 100644 index 9e61223eac9..00000000000 --- a/examples/webserver/static-content/src/main/java/io/helidon/examples/webserver/staticcontent/package-info.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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. - */ - -/** - * Application demonstrates combination of the static content with a simple REST API. It counts accesses and display it - * on the WEB page. - *

        - * Start with {@link io.helidon.examples.webserver.staticcontent.Main} class. - * - * @see io.helidon.examples.webserver.staticcontent.Main - */ -package io.helidon.examples.webserver.staticcontent; diff --git a/examples/webserver/static-content/src/main/resources/WEB/css/app.css b/examples/webserver/static-content/src/main/resources/WEB/css/app.css deleted file mode 100644 index b990bfb07b1..00000000000 --- a/examples/webserver/static-content/src/main/resources/WEB/css/app.css +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2017, 2021 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. - */ - -body { - padding-top: 2rem; -} diff --git a/examples/webserver/static-content/src/main/resources/WEB/index.html b/examples/webserver/static-content/src/main/resources/WEB/index.html deleted file mode 100644 index f75189908b7..00000000000 --- a/examples/webserver/static-content/src/main/resources/WEB/index.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - - - Static Content Example - - - - - - - -

        - - -
        -
        -

        Hello!

        -

        -
        -
        - -
        - -
        -
        -

        Heading

        -

        Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui.

        -

        View details »

        -
        -
        -

        Heading

        -

        Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui.

        -

        View details »

        -
        -
        -

        Heading

        -

        Donec sed odio dui. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Vestibulum id ligula porta felis euismod semper. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.

        -

        View details »

        -
        -
        - -
        - -
        -

        © Oracle 2017

        -
        -
        - - - - - - - diff --git a/examples/webserver/static-content/src/main/resources/WEB/js/app.js b/examples/webserver/static-content/src/main/resources/WEB/js/app.js deleted file mode 100644 index b2c8d0b3abd..00000000000 --- a/examples/webserver/static-content/src/main/resources/WEB/js/app.js +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2017, 2021 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. - */ - -$(document).ready(function() { - $.get("api/counter", function (data) { - $("#hello-message").html("This page was reloaded " + data.api + " times. " - + "This WebServer already served " + data.all + " requests."); - }); -}); diff --git a/examples/webserver/static-content/src/test/java/io/helidon/examples/webserver/staticcontent/MainTest.java b/examples/webserver/static-content/src/test/java/io/helidon/examples/webserver/staticcontent/MainTest.java deleted file mode 100644 index d6e3ccce170..00000000000 --- a/examples/webserver/static-content/src/test/java/io/helidon/examples/webserver/staticcontent/MainTest.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2023 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.webserver.staticcontent; - -import io.helidon.http.Status; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.http.HttpRouting; -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpRoute; - -import jakarta.json.JsonNumber; -import jakarta.json.JsonObject; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -@ServerTest -class MainTest { - - private final Http1Client client; - - protected MainTest(Http1Client client) { - this.client = client; - } - - @SetUpRoute - static void routing(HttpRouting.Builder builder) { - Main.routing(builder); - } - - @Test - void testUi() { - assertThat(allCounter(), is(1)); - try (Http1ClientResponse response = client.get("/ui/index.html").request()) { - assertThat(response.status(), is(Status.OK_200)); - assertThat(response.headers().contentType().orElseThrow().text(), is("text/html")); - } - try (Http1ClientResponse response = client.get("/ui/css/app.css").request()) { - assertThat(response.status(), is(Status.OK_200)); - assertThat(response.headers().contentType().orElseThrow().text(), is("text/css")); - } - try (Http1ClientResponse response = client.get("/ui/js/app.js").request()) { - assertThat(response.status(), is(Status.OK_200)); - assertThat(response.headers().contentType().orElseThrow().text(), is("text/javascript")); - } - assertThat(allCounter(), is(5)); // includes /ui/api/counter calls - } - - private int allCounter() { - try (Http1ClientResponse response = client.get("/ui/api/counter").request()) { - assertThat(response.status(), is(Status.OK_200)); - JsonNumber number = (JsonNumber) response.as(JsonObject.class).get("all"); - return number.intValue(); - } - } -} diff --git a/examples/webserver/streaming/README.md b/examples/webserver/streaming/README.md deleted file mode 100644 index 29bf4534003..00000000000 --- a/examples/webserver/streaming/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# Streaming Example - -This application is an example of a very simple streaming service. It leverages the -fact that Helidon uses virtual threads to perform simple input/output stream blocking -operations in the endpoint handlers. As a result, this service runs in constant space instead -of proportional to the size of the file being uploaded or downloaded. - -There are two endpoints: - -- `upload` : uploads a file to the service -- `download` : downloads the previously uploaded file - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-webserver-streaming.jar -``` - -Upload a file and download it back with `curl`: -```shell -curl --data-binary "@large-file.bin" http://localhost:8080/upload -curl http://localhost:8080/download --output myfile.bin -``` diff --git a/examples/webserver/streaming/large-file.bin b/examples/webserver/streaming/large-file.bin deleted file mode 100644 index 909e3e3e9bcc1e7b1993f3f5abd1532a938df436..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeIuF#!Mo0K%a4Pi+kkh(KY$fB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM Y7%*VKfB^#r3>YwAz<>b*1`NCp3@`uy0RR91 diff --git a/examples/webserver/streaming/pom.xml b/examples/webserver/streaming/pom.xml deleted file mode 100644 index a6069f4c441..00000000000 --- a/examples/webserver/streaming/pom.xml +++ /dev/null @@ -1,88 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.webserver - helidon-examples-webserver-streaming - Helidon Examples WebServer Streaming - - - Application that demonstrates how to write a service that uploads and downloads - a file using chunks, in a streaming manner. - - - - io.helidon.examples.webserver.streaming.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.logging - helidon-logging-jul - runtime - - - org.junit.jupiter - junit-jupiter-api - test - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - io.helidon.webclient - helidon-webclient - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/webserver/streaming/src/main/java/io/helidon/examples/webserver/streaming/Main.java b/examples/webserver/streaming/src/main/java/io/helidon/examples/webserver/streaming/Main.java deleted file mode 100644 index dc587a7e638..00000000000 --- a/examples/webserver/streaming/src/main/java/io/helidon/examples/webserver/streaming/Main.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2018, 2024 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.webserver.streaming; - -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.http.HttpRouting; - -/** - * Class Main. Entry point to streaming application. - */ -public class Main { - - private Main() { - } - - /** - * Setup {@link HttpRouting}. - */ - static void routing(HttpRouting.Builder routing) { - routing.register(new StreamingService()); - } - - /** - * A java main class. - * - * @param args command line arguments. - */ - public static void main(String[] args) { - WebServerConfig.Builder builder = WebServer.builder().port(8080); - builder.routing(Main::routing); - WebServer server = builder.build().start(); - System.out.println("Steaming service is up at http://localhost:" + server.port()); - } -} diff --git a/examples/webserver/streaming/src/main/java/io/helidon/examples/webserver/streaming/StreamingService.java b/examples/webserver/streaming/src/main/java/io/helidon/examples/webserver/streaming/StreamingService.java deleted file mode 100644 index 81c83523d01..00000000000 --- a/examples/webserver/streaming/src/main/java/io/helidon/examples/webserver/streaming/StreamingService.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2018, 2024 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.webserver.streaming; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardCopyOption; -import java.util.logging.Logger; - -import io.helidon.http.Status; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -/** - * StreamingService class. - * Uses a {@link java.io.InputStream} and {@link java.io.OutputStream} for uploading and downloading files. - */ -public class StreamingService implements HttpService { - private static final Logger LOGGER = Logger.getLogger(StreamingService.class.getName()); - - // Last file uploaded (or default). Since we don't do any locking - // when operating on the file this example is not safe for concurrent requests. - private volatile Path filePath; - - StreamingService() { - } - - @Override - public void routing(HttpRules rules) { - rules.get("/download", this::download) - .post("/upload", this::upload); - } - - private void upload(ServerRequest request, ServerResponse response) { - LOGGER.info("Entering upload ... " + Thread.currentThread()); - try { - Path tempFilePath = Files.createTempFile("large-file", ".tmp"); - Files.copy(request.content().inputStream(), tempFilePath, StandardCopyOption.REPLACE_EXISTING); - filePath = tempFilePath; - response.send("File was stored as " + tempFilePath); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - LOGGER.info("Exiting upload after uploading " + filePath.toFile().length() + " bytes..."); - } - - private void download(ServerRequest request, ServerResponse response) { - LOGGER.info("Entering download ..." + Thread.currentThread()); - if (filePath == null) { - response.status(Status.BAD_REQUEST_400).send("No file to download. Please upload file first."); - return; - } - long length = filePath.toFile().length(); - response.headers().contentLength(length); - try { - Files.copy(filePath, response.outputStream()); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - LOGGER.info("Exiting download after serving " + length + " bytes..."); - } -} - diff --git a/examples/webserver/streaming/src/main/java/io/helidon/examples/webserver/streaming/package-info.java b/examples/webserver/streaming/src/main/java/io/helidon/examples/webserver/streaming/package-info.java deleted file mode 100644 index 48157a583ef..00000000000 --- a/examples/webserver/streaming/src/main/java/io/helidon/examples/webserver/streaming/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2018, 2023 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. - */ - -/** - *

        - * Start with {@link io.helidon.examples.webserver.streaming.Main} class. - * - * @see io.helidon.examples.webserver.streaming.Main - */ -package io.helidon.examples.webserver.streaming; diff --git a/examples/webserver/streaming/src/test/java/io/helidon/examples/webserver/streaming/MainTest.java b/examples/webserver/streaming/src/test/java/io/helidon/examples/webserver/streaming/MainTest.java deleted file mode 100644 index 50ada67ebe6..00000000000 --- a/examples/webserver/streaming/src/test/java/io/helidon/examples/webserver/streaming/MainTest.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2024 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.webserver.streaming; - -import io.helidon.http.Status; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.http.HttpRouting; -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpRoute; - -import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -@ServerTest -@TestMethodOrder(MethodOrderer.OrderAnnotation.class) -class MainTest { - - private final Http1Client client; - - private final String TEST_DATA_1 = "Test Data 1"; - private final String TEST_DATA_2 = "Test Data 2"; - - protected MainTest(Http1Client client) { - this.client = client; - } - - @SetUpRoute - static void routing(HttpRouting.Builder builder) { - Main.routing(builder); - } - - @Test - @Order(0) - void testBadRequest() { - try (Http1ClientResponse response = client.get("/download").request()) { - assertThat(response.status(), is(Status.BAD_REQUEST_400)); - } - } - - @Test - @Order(1) - void testUpload1() { - try (Http1ClientResponse response = client.post("/upload").submit(TEST_DATA_1)) { - assertThat(response.status(), is(Status.OK_200)); - } - } - - @Test - @Order(2) - void testDownload1() { - try (Http1ClientResponse response = client.get("/download").request()) { - assertThat(response.status(), is(Status.OK_200)); - assertThat(response.as(String.class), is(TEST_DATA_1)); - } - } - - @Test - @Order(3) - void testUpload2() { - try (Http1ClientResponse response = client.post("/upload").submit(TEST_DATA_2)) { - assertThat(response.status(), is(Status.OK_200)); - } - } - - @Test - @Order(4) - void testDownload2() { - try (Http1ClientResponse response = client.get("/download").request()) { - assertThat(response.status(), is(Status.OK_200)); - assertThat(response.as(String.class), is(TEST_DATA_2)); - } - } -} diff --git a/examples/webserver/threads/README.md b/examples/webserver/threads/README.md deleted file mode 100644 index 7c3b5355c93..00000000000 --- a/examples/webserver/threads/README.md +++ /dev/null @@ -1,98 +0,0 @@ -# Helidon SE Threading Example - -Helidon's adoption of virtual threads has eliminated a lot of the headaches -of thread pools and thread pool tuning. But there are still cases where using -application specific executors is desirable. This example illustrates two -such cases: - -1. Using a virtual thread executor to execute multiple tasks in parallel. -2. Using a platform thread executor to execute long-running CPU intensive operations. - -## Build and run - -```bash -mvn package -java -jar target/helidon-examples-webserver-threads.jar -``` - -## Exercise the application - -__Compute:__ -``` -curl -X GET http://localhost:8080/thread/compute/5 -``` -The `compute` endpoint runs a costly floating point computation using a platform thread. -Increase the number to make the computation more costly (and take longer). - -The request returns the results of the computation (not important!). - -__Fanout:__ -``` -curl -X GET http://localhost:8080/thread/fanout/5 -``` -The `fanout` endpoint simulates a fanout of remote calls that are run in parallel using -virtual threads. Each remote call invokes the server's `sleep` endpoint sleeping anywhere from -0 to 4 seconds. Since the remote requests are executed in parallel the curl request should not -take longer than 4 seconds to return. Increase the number to have more remote calls made -in parallel. - -The request returns a list of numbers showing the sleep value of each remote client call. - -__Sleep:__ -``` -curl -X GET http://localhost:8080/thread/sleep/4 -``` -This is a simple endpoint that just sleeps for the specified number of seconds. It is -used by the `fanout` endpoint. - -The request returns the number of seconds requested to sleep. - -## Further Discussion - -### Use Case 1: Virtual Threads: Executing Tasks in Parallel - -Sometimes an endpoint needs to perform multiple blocking operations in parallel: -querying a database, calling another service, etc. Virtual threads are a -good fit for this because they are lightweight and do not consume platform -threads when performing blocking operations (like network I/O). - -The `fanout` endpoint in this example demonstrates this use case. You pass the endpoint -the number of parallel tasks to execute and it simulates remote client calls by using -the Helidon WebClient to call the `sleep` endpoint on the server. - -### Use Case 2: Platform Threads: Executing a CPU Intensive Task - -If you have an endpoint that performs an in-memory, CPU intensive task, then -platform threads might be a better match. This is because a virtual thread would be pinned to -a platform thread throughout the computation -- potentially causing unbounded consumption -of platform threads. Instead, the example uses a small, bounded pool of platform -threads to perform computations. Bounded meaning that the number of threads and the -size of the work queue are both limited and will reject work when they fill up. -This gives the application tight control over the resources allocated to these CPU intensive tasks. - -The `compute` endpoint in this example demonstrates this use case. You pass the endpoint -the number of times you want to make the computation, and it uses a small bounded pool -of platform threads to execute the task. - -### Use of Helidon's ThreadPoolSupplier and Configuration - -This example uses `io.helidon.common.configurable.ThreadPoolSupplier` to create the -two executors used in the example. This provides a few benefits: - -1. ThreadPoolSupplier supports a number of tuning parameters that enable us to configure a small, bounded threadpool. -2. You can drive the thread pool configuration via Helidon config -- see this example's `application.yaml` -3. You get propagation of Helidon's Context which supports Helidon's features as well as direct use by the application. - -### Logging - -In `logging.properties` the log level for `io.helidon.common.configurable.ThreadPool` -is increased so that you can see the values used to configure the platform thread pool. -When you start the application you will see a line like -``` -ThreadPool 'application-platform-executor-thread-pool-1' {corePoolSize=1, maxPoolSize=2, - queueCapacity=10, growthThreshold=1000, growthRate=0%, averageQueueSize=0.00, peakQueueSize=0, averageActiveThreads=0.00, peakPoolSize=0, currentPoolSize=0, completedTasks=0, failedTasks=0, rejectedTasks=0} -``` -This reflects the configuration of the platform thread pool created by the application -and used by the `compute` endpoint. At most the thread pool will consume two platform -threads for computations. The work queue is limited to 10 entries to allow for small -bursts of requests. diff --git a/examples/webserver/threads/pom.xml b/examples/webserver/threads/pom.xml deleted file mode 100644 index a201c6abe85..00000000000 --- a/examples/webserver/threads/pom.xml +++ /dev/null @@ -1,85 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.webserver - helidon-examples-webserver-threads - 4.1.0-SNAPSHOT - - - io.helidon.examples.webserver.threads.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webclient - helidon-webclient - - - io.helidon.config - helidon-config-yaml - - - io.helidon.logging - helidon-logging-jul - runtime - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/webserver/threads/src/main/java/io/helidon/examples/webserver/threads/Main.java b/examples/webserver/threads/src/main/java/io/helidon/examples/webserver/threads/Main.java deleted file mode 100644 index 41e008633c1..00000000000 --- a/examples/webserver/threads/src/main/java/io/helidon/examples/webserver/threads/Main.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2024 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.webserver.threads; - -import io.helidon.logging.common.LogConfig; -import io.helidon.config.Config; -import io.helidon.webclient.api.WebClient; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.http.HttpRouting; - -/** - * The application main class. - */ -public class Main { - - static WebClient webclient; - - /** - * Cannot be instantiated. - */ - private Main() { - } - - /** - * Application main entry point. - * @param args command line arguments. - */ - public static void main(String[] args) { - - // load logging configuration - LogConfig.configureRuntime(); - - // initialize global config from default configuration - Config config = Config.create(); - Config.global(config); - - WebServer webserver = WebServer.builder() - .config(config.get("server")) - .routing(Main::routing) - .build() - .start(); - - // Construct webclient here using port of running server - webclient = WebClient.builder() - .baseUri("http://localhost:" + webserver.port() + "/thread") - .build(); - - System.out.println("WEB server is up! http://localhost:" + webserver.port() + "/thread"); - } - - - /** - * Updates HTTP Routing. - */ - static void routing(HttpRouting.Builder routing) { - routing - .register("/thread", new ThreadService()); - } -} \ No newline at end of file diff --git a/examples/webserver/threads/src/main/java/io/helidon/examples/webserver/threads/ThreadService.java b/examples/webserver/threads/src/main/java/io/helidon/examples/webserver/threads/ThreadService.java deleted file mode 100644 index 60ece4b13b3..00000000000 --- a/examples/webserver/threads/src/main/java/io/helidon/examples/webserver/threads/ThreadService.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (c) 2024 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.webserver.threads; - -import java.lang.System.Logger.Level; -import java.util.ArrayList; -import java.util.Random; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; -import java.util.concurrent.RejectedExecutionException; - -import io.helidon.common.configurable.ThreadPoolSupplier; -import io.helidon.config.Config; -import io.helidon.http.Status; -import io.helidon.webclient.api.ClientResponseTyped; -import io.helidon.webclient.api.WebClient; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -class ThreadService implements HttpService { - - private static final System.Logger LOGGER = System.getLogger(ThreadService.class.getName()); - private static final Random rand = new Random(System.currentTimeMillis()); - - // ThreadPool of platform threads. - private static ExecutorService platformExecutorService; - // Executor of virtual threads. - private static ExecutorService virtualExecutorService; - - /** - * The config value for the key {@code greeting}. - */ - - ThreadService() { - this(Config.global().get("app")); - } - - ThreadService(Config appConfig) { - /* - * We create two executor services. One is a thread pool of platform threads. - * The second is a virtual thread executor service. - * See `application.yaml` for configuration of each of these. - */ - ThreadPoolSupplier platformThreadSupplier = ThreadPoolSupplier.builder() - .config(appConfig.get("application-platform-executor")) - .build(); - platformExecutorService = platformThreadSupplier.get(); - - ThreadPoolSupplier virtualThreadSupplier = ThreadPoolSupplier.builder() - .config(appConfig.get("application-virtual-executor")) - .build(); - virtualExecutorService = virtualThreadSupplier.get(); - } - - @Override - public void routing(HttpRules rules) { - rules - .get("/compute", this::computeHandler) - .get("/compute/{iterations}", this::computeHandler) - .get("/fanout", this::fanOutHandler) - .get("/fanout/{count}", this::fanOutHandler) - .get("/sleep", this::sleepHandler) - .get("/sleep/{seconds}", this::sleepHandler); - } - - /** - * Perform a CPU intensive operation. - * The optional path parameter controls the number of iterations of the computation. The more - * iterations the longer it will take. - * - * @param request server request - * @param response server response - */ - private void computeHandler(ServerRequest request, ServerResponse response) { - int iterations = request.path().pathParameters().first("iterations").asInt().orElse(1); - try { - // We execute the computation on a platform thread. This prevents unbounded obstruction of virtual - // threads, plus provides us the ability to limit the number of concurrent computation requests - // we handle by limiting the thread pool work queue length (as defined in application.yaml) - Future future = platformExecutorService.submit(() -> compute(iterations)); - response.send(future.get().toString()); - } catch (RejectedExecutionException e) { - // Work queue is full! We reject the request - LOGGER.log(Level.WARNING, e); - response.status(Status.SERVICE_UNAVAILABLE_503).send("Server busy"); - } catch (ExecutionException | InterruptedException e) { - LOGGER.log(Level.ERROR, e); - response.status(Status.INTERNAL_SERVER_ERROR_500).send(); - } - } - - /** - * Sleep for a specified number of seconds. - * The optional path parameter controls the number of seconds to sleep. Defaults to 1 - * - * @param request server request - * @param response server response - */ - private void sleepHandler(ServerRequest request, ServerResponse response) { - int seconds = request.path().pathParameters().first("seconds").asInt().orElse(1); - response.send(String.valueOf(sleep(seconds))); - } - - /** - * Fan out a number of remote requests in parallel. - * The optional path parameter controls the number of parallel requests to make. - * - * @param request server request - * @param response server response - */ - private void fanOutHandler(ServerRequest request, ServerResponse response) { - int count = request.path().pathParameters().first("count").asInt().orElse(1); - LOGGER.log(Level.INFO, "Fanning out " + count + " parallel requests"); - // We simulate multiple client requests running in parallel by calling our sleep endpoint. - try { - // For this we use our virtual thread based executor. We submit the work and save the Futures - var futures = new ArrayList>(); - for (int i = 0; i < count; i++) { - futures.add(virtualExecutorService.submit(() -> callRemote(rand.nextInt(5)))); - } - - // After work has been submitted we loop through the future and block getting the results. - // We aggregate the results in a list of Strings - var responses = new ArrayList(); - for (var future : futures) { - try { - responses.add(future.get()); - } catch (InterruptedException e) { - responses.add(e.getMessage()); - } - } - - // All parallel calls are complete! - response.send(String.join(":", responses)); - } catch (ExecutionException e) { - LOGGER.log(Level.ERROR, e); - response.status(Status.INTERNAL_SERVER_ERROR_500).send(); - } - } - - /** - * Simulate a remote client call by calling this server's sleep endpoint - * - * @param seconds number of seconds the endpoint should sleep. - * @return string response from client - */ - private String callRemote(int seconds) { - LOGGER.log(Level.INFO, Thread.currentThread() + ": Calling remote sleep for " + seconds + "s"); - WebClient client = Main.webclient; - ClientResponseTyped response = client.get("/sleep/" + seconds).request(String.class); - if (response.status().equals(Status.OK_200)) { - return response.entity(); - } - return response.status().toString(); - } - - /** - * Sleep current thread - * - * @param seconds number of seconds to sleep - * @return number of seconds requested to sleep - */ - private int sleep(int seconds) { - try { - Thread.sleep(seconds * 1_000L); - } catch (InterruptedException e) { - LOGGER.log(Level.WARNING, e); - } - return seconds; - } - - /** - * Perform a CPU intensive computation - * - * @param iterations: number of times to perform computation - * @return result of computation - */ - private double compute(int iterations) { - LOGGER.log(Level.INFO, Thread.currentThread() + ": Computing with " + iterations + " iterations"); - double d = 123456789.123456789 * rand.nextInt(100); - for (int i = 0; i < iterations; i++) { - for (int n = 0; n < 1_000_000; n++) { - for (int j = 0; j < 5; j++) { - d = Math.tan(d); - d = Math.atan(d); - } - } - } - return d; - } -} diff --git a/examples/webserver/threads/src/main/java/io/helidon/examples/webserver/threads/package-info.java b/examples/webserver/threads/src/main/java/io/helidon/examples/webserver/threads/package-info.java deleted file mode 100644 index f7dfc7e8a4e..00000000000 --- a/examples/webserver/threads/src/main/java/io/helidon/examples/webserver/threads/package-info.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) 2024 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.webserver.threads; diff --git a/examples/webserver/threads/src/main/resources/application.yaml b/examples/webserver/threads/src/main/resources/application.yaml deleted file mode 100644 index 05ee0f283e5..00000000000 --- a/examples/webserver/threads/src/main/resources/application.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# -# Copyright (c) 2024 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 - -app: - application-platform-executor: - thread-name-prefix: "application-platform-executor-" - core-pool-size: 1 - max-pool-size: 2 - queue-capacity: 10 - application-virtual-executor: - thread-name-prefix: "application-virtual-executor-" - virtual-threads: true diff --git a/examples/webserver/threads/src/main/resources/logging.properties b/examples/webserver/threads/src/main/resources/logging.properties deleted file mode 100644 index 5fddb7f3d50..00000000000 --- a/examples/webserver/threads/src/main/resources/logging.properties +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) 2024 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. -# - -handlers=io.helidon.logging.jul.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS.%1$tL %5$s%6$s%n -# Global logging level. Can be overridden by specific loggers -.level=INFO - -io.helidon.common.configurable.ThreadPool.level=ALL diff --git a/examples/webserver/threads/src/test/java/io/helidon/examples/webserver/threads/MainTest.java b/examples/webserver/threads/src/test/java/io/helidon/examples/webserver/threads/MainTest.java deleted file mode 100644 index bbe78c10f9a..00000000000 --- a/examples/webserver/threads/src/test/java/io/helidon/examples/webserver/threads/MainTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2024 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.webserver.threads; - -import io.helidon.http.Status; -import io.helidon.webclient.api.HttpClientResponse; -import io.helidon.webclient.api.WebClient; -import io.helidon.webserver.http.HttpRouting; -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpRoute; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -@ServerTest -class MainTest { - private final WebClient client; - - protected MainTest(WebClient client) { - this.client = client; - Main.webclient = this.client; // Needed for ThreadService to make calls - } - - @SetUpRoute - static void routing(HttpRouting.Builder builder) { - Main.routing(builder); - } - - @Test - void testFanOut() { - try (HttpClientResponse response = client.get("/thread/fanout/2").request()) { - assertThat(response.status(), is(Status.OK_200)); - } - } - - @Test - void testCompute() { - try (HttpClientResponse response = client.get("/thread/compute").request()) { - assertThat(response.status(), is(Status.OK_200)); - } - } -} \ No newline at end of file diff --git a/examples/webserver/tls/pom.xml b/examples/webserver/tls/pom.xml deleted file mode 100644 index 9ec5325a33b..00000000000 --- a/examples/webserver/tls/pom.xml +++ /dev/null @@ -1,86 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - - io.helidon.examples.webserver - helidon-examples-webserver-tls - Helidon Examples WebServer TLS - - - Application demonstrates TLS configuration using a builder - and config. - - - - io.helidon.examples.webserver.tls.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.config - helidon-config-yaml - - - io.helidon.logging - helidon-logging-jul - runtime - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/webserver/tls/src/main/java/io/helidon/examples/webserver/tls/Main.java b/examples/webserver/tls/src/main/java/io/helidon/examples/webserver/tls/Main.java deleted file mode 100644 index 28d98f33753..00000000000 --- a/examples/webserver/tls/src/main/java/io/helidon/examples/webserver/tls/Main.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2020, 2024 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.webserver.tls; - -import io.helidon.common.configurable.Resource; -import io.helidon.config.Config; -import io.helidon.logging.common.LogConfig; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.http.HttpRouting; - -/** - * Main class of TLS example. - */ -public final class Main { - - // utility class - private Main() { - } - - /** - * Start the example. - * This will start two Helidon WebServers, both protected by TLS - one configured from config, one using a builder. - * Port of the servers will be configured from config, to be able to switch to an ephemeral port for tests. - * - * @param args start arguments are ignored - */ - public static void main(String[] args) { - LogConfig.configureRuntime(); - - Config config = Config.create(); - - WebServerConfig.Builder builder1 = WebServer.builder(); - setupConfigBased(builder1, config.get("config-based")); - WebServer server1 = builder1.build().start(); - System.out.println("Started config based WebServer on https://localhost:" + server1.port()); - - WebServerConfig.Builder builder2 = WebServer.builder() - .config(config.get("builder-based")); // we want port to be configurable always - setupBuilderBased(builder2); - WebServer server2 = builder2.build().start(); - System.out.println("Started builder based WebServer on http://localhost:" + server2.port()); - } - - static void setupBuilderBased(WebServerConfig.Builder server) { - server.routing(Main::routing) - .tls(tls -> tls - .privateKey(key -> key - .keystore(store -> store - .passphrase("changeit") - .keystore(Resource.create("server.p12")))) - .privateKeyCertChain(key -> key - .keystore(store -> store - .passphrase("changeit") - .keystore(Resource.create("server.p12"))))); - } - - static void setupConfigBased(WebServerConfig.Builder server, Config config) { - server.config(config) - .routing(Main::routing); - } - - static void routing(HttpRouting.Builder routing) { - routing.get("/", (req, res) -> res.send("Hello!")); - } -} diff --git a/examples/webserver/tls/src/main/java/io/helidon/examples/webserver/tls/package-info.java b/examples/webserver/tls/src/main/java/io/helidon/examples/webserver/tls/package-info.java deleted file mode 100644 index 49d91fcd025..00000000000 --- a/examples/webserver/tls/src/main/java/io/helidon/examples/webserver/tls/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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 of TLS configuration for webserver, using both {@link io.helidon.config.Config} and builder based approach. - */ -package io.helidon.examples.webserver.tls; diff --git a/examples/webserver/tls/src/main/resources/application.yaml b/examples/webserver/tls/src/main/resources/application.yaml deleted file mode 100644 index dcbd7702801..00000000000 --- a/examples/webserver/tls/src/main/resources/application.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright (c) 2020, 2024 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. -# - -config-based: - port: 8080 - tls: - private-key: - keystore: - passphrase: "changeit" - resource: - resource-path: "server.p12" - -builder-based: - port: 8081 diff --git a/examples/webserver/tls/src/main/resources/logging.properties b/examples/webserver/tls/src/main/resources/logging.properties deleted file mode 100644 index df9085e5a84..00000000000 --- a/examples/webserver/tls/src/main/resources/logging.properties +++ /dev/null @@ -1,19 +0,0 @@ -# -# Copyright (c) 2020, 2023 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. -# - -handlers=io.helidon.logging.jul.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=[%1$tc] %4$s: %2$s - %5$s %6$s%n -.level=INFO diff --git a/examples/webserver/tls/src/main/resources/server.p12 b/examples/webserver/tls/src/main/resources/server.p12 deleted file mode 100644 index a692efcf98ddc979a8875da4671294f37ce7b7b7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4218 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 - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - - io.helidon.examples.webserver - helidon-examples-webserver-tracing - Helidon Examples WebServer Tracing - - - io.helidon.examples.webserver.tracing.TracingMain - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver - helidon-webserver-http2 - - - io.helidon.webserver.observe - helidon-webserver-observe-tracing - - - io.helidon.webclient - helidon-webclient - - - io.helidon.webclient - helidon-webclient-tracing - - - io.helidon.tracing.providers - helidon-tracing-providers-jaeger - - - io.helidon.config - helidon-config-yaml - - - io.helidon.logging - helidon-logging-jul - runtime - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/webserver/tracing/src/main/java/io/helidon/examples/webserver/tracing/TracingMain.java b/examples/webserver/tracing/src/main/java/io/helidon/examples/webserver/tracing/TracingMain.java deleted file mode 100644 index 9a702013d33..00000000000 --- a/examples/webserver/tracing/src/main/java/io/helidon/examples/webserver/tracing/TracingMain.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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.webserver.tracing; - -import io.helidon.logging.common.LogConfig; -import io.helidon.tracing.Span; -import io.helidon.tracing.Tracer; -import io.helidon.tracing.TracerBuilder; -import io.helidon.webclient.api.WebClient; -import io.helidon.webclient.tracing.WebClientTracing; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.http.Handler; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; -import io.helidon.webserver.http1.Http1Route; -import io.helidon.webserver.http2.Http2Route; -import io.helidon.webserver.observe.ObserveFeature; -import io.helidon.webserver.observe.tracing.TracingObserver; - -import static io.helidon.http.Method.GET; - -/** - * Tracing example. - */ -public class TracingMain { - private TracingMain() { - } - - /** - * Main method. - * @param args ignored - */ - public static void main(String[] args) { - LogConfig.configureRuntime(); - - Tracer tracer = TracerBuilder.create("helidon") - .build(); - - WebServer.builder() - .port(8080) - .host("127.0.0.1") - .addFeature(ObserveFeature.builder() - .addObserver(TracingObserver.create(tracer)) - .build()) - .routing(router -> router - .route(Http1Route.route(GET, "/versionspecific", new TracedHandler(tracer, "HTTP/1.1 route"))) - .route(Http2Route.route(GET, "/versionspecific", new TracedHandler(tracer, "HTTP/2 route"))) - .get("/client", new ClientHandler(tracer))) - .build() - .start(); - } - - private static class ClientHandler implements Handler { - private final WebClient client; - - private ClientHandler(Tracer tracer) { - this.client = WebClient.builder() - .baseUri("http://localhost:8080/versionspecific") - .servicesDiscoverServices(false) - .addService(WebClientTracing.create(tracer)) - .build(); - } - - @Override - public void handle(ServerRequest req, ServerResponse res) { - res.send(client.get() - .requestEntity(String.class)); - } - } - - private static class TracedHandler implements Handler { - private final Tracer tracer; - private final String message; - - private TracedHandler(Tracer tracer, String message) { - this.tracer = tracer; - this.message = message; - } - - @Override - public void handle(ServerRequest req, ServerResponse res) { - Span span = tracer.spanBuilder("custom-span") - .start(); - try { - span.addEvent("my nice log"); - res.send(message); - } finally { - span.end(); - } - } - } -} diff --git a/examples/webserver/tracing/src/main/java/io/helidon/examples/webserver/tracing/package-info.java b/examples/webserver/tracing/src/main/java/io/helidon/examples/webserver/tracing/package-info.java deleted file mode 100644 index cac9c63c60f..00000000000 --- a/examples/webserver/tracing/src/main/java/io/helidon/examples/webserver/tracing/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2022, 2023 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. - */ - -/** - * Tracing example. - */ -package io.helidon.examples.webserver.tracing; diff --git a/examples/webserver/tracing/src/main/resources/application.yaml b/examples/webserver/tracing/src/main/resources/application.yaml deleted file mode 100644 index 97809cc4f26..00000000000 --- a/examples/webserver/tracing/src/main/resources/application.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2022, 2023 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. -# - -tracing: - service: "helidon-server" - sampler-type: "const" - sampler-param: 1 \ No newline at end of file diff --git a/examples/webserver/tracing/src/main/resources/logging.properties b/examples/webserver/tracing/src/main/resources/logging.properties deleted file mode 100644 index d09df1098a3..00000000000 --- a/examples/webserver/tracing/src/main/resources/logging.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2022, 2023 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. -# -handlers=java.util.logging.ConsoleHandler -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS.%1$tL %5$s%6$s%n -# Global logging level. Can be overridden by specific loggers -.level=INFO -io.helidon.webserver.level=INFO diff --git a/examples/webserver/tutorial/README.md b/examples/webserver/tutorial/README.md deleted file mode 100644 index 89c9e6d6d74..00000000000 --- a/examples/webserver/tutorial/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Tutorial Server - -This application demonstrates various WebServer use cases together and in its complexity. - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-webserver-tutorial.jar -``` diff --git a/examples/webserver/tutorial/pom.xml b/examples/webserver/tutorial/pom.xml deleted file mode 100644 index 0d5d7d9d89e..00000000000 --- a/examples/webserver/tutorial/pom.xml +++ /dev/null @@ -1,84 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.webserver - helidon-examples-webserver-tutorial - Helidon Examples WebServer Tutorial - - - A tutorial documentation server. - It serves various tutorial articles designed based on project examples. - It is also a complex example demonstrating various web server features. - - - - io.helidon.examples.webserver.tutorial.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.logging - helidon-logging-jul - runtime - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/webserver/tutorial/src/main/java/io/helidon/examples/webserver/tutorial/Comment.java b/examples/webserver/tutorial/src/main/java/io/helidon/examples/webserver/tutorial/Comment.java deleted file mode 100644 index fe5b75b9634..00000000000 --- a/examples/webserver/tutorial/src/main/java/io/helidon/examples/webserver/tutorial/Comment.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2023 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.webserver.tutorial; - -/** - * Represents a single comment. - */ -record Comment(User user, String message) { - - @Override - public String toString() { - StringBuilder result = new StringBuilder(); - if (user != null) { - result.append(user.alias()); - } - result.append(": "); - result.append(message); - return result.toString(); - } -} diff --git a/examples/webserver/tutorial/src/main/java/io/helidon/examples/webserver/tutorial/CommentService.java b/examples/webserver/tutorial/src/main/java/io/helidon/examples/webserver/tutorial/CommentService.java deleted file mode 100644 index 7517cd57fdb..00000000000 --- a/examples/webserver/tutorial/src/main/java/io/helidon/examples/webserver/tutorial/CommentService.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.webserver.tutorial; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; - -import io.helidon.http.HttpMediaTypes; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -/** - * Basic service for comments. - */ -class CommentService implements HttpService { - - private final ConcurrentHashMap> data = new ConcurrentHashMap<>(); - - @Override - public void routing(HttpRules rules) { - rules.get("/{room-id}", this::getComments) - .post("/{room-id}", this::addComment); - } - - private void getComments(ServerRequest req, ServerResponse resp) { - String roomId = req.path().pathParameters().get("room-id"); - resp.headers().contentType(HttpMediaTypes.PLAINTEXT_UTF_8); - resp.send(getComments(roomId)); - } - - /** - * Returns all comments for the room or an empty list if room doesn't exist. - * - * @param roomId a room ID - * @return a list of comments - */ - List getComments(String roomId) { - if (roomId == null || roomId.isEmpty()) { - return Collections.emptyList(); - } - - List result = data.get(roomId); - return result == null ? Collections.emptyList() : result; - } - - private void addComment(ServerRequest req, ServerResponse res) { - String roomId = req.path().pathParameters().get("room-id"); - User user = req.context().get(User.class).orElse(User.ANONYMOUS); - String msg = req.content().as(String.class); - addComment(roomId, user, msg); - res.send(); - } - - /** - * Adds new comment into the comment-room. - * - * @param roomName a name of the comment-room - * @param user a user who provides the comment - * @param message a comment message - */ - void addComment(String roomName, User user, String message) { - if (user == null) { - user = User.ANONYMOUS; - } - List comments = data.computeIfAbsent(roomName, k -> Collections.synchronizedList(new ArrayList<>())); - comments.add(new Comment(user, message)); - } - -} diff --git a/examples/webserver/tutorial/src/main/java/io/helidon/examples/webserver/tutorial/CommentSupport.java b/examples/webserver/tutorial/src/main/java/io/helidon/examples/webserver/tutorial/CommentSupport.java deleted file mode 100644 index 0806b82a8d7..00000000000 --- a/examples/webserver/tutorial/src/main/java/io/helidon/examples/webserver/tutorial/CommentSupport.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2023 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.webserver.tutorial; - -import java.util.List; - -import io.helidon.common.GenericType; -import io.helidon.http.Headers; -import io.helidon.http.WritableHeaders; -import io.helidon.http.media.MediaSupport; - -class CommentSupport implements MediaSupport { - - private static final GenericType> COMMENT_TYPE = new GenericType<>() {}; - - @Override - @SuppressWarnings("unchecked") - public WriterResponse writer(GenericType type, - Headers requestHeaders, - WritableHeaders responseHeaders) { - if (!COMMENT_TYPE.rawType().isAssignableFrom(type.rawType())) { - return WriterResponse.unsupported(); - } - return (WriterResponse) new WriterResponse<>(SupportLevel.SUPPORTED, CommentWriter::new); - } - - @Override - public String name() { - return "comment"; - } - - @Override - public String type() { - return "comment"; - } -} diff --git a/examples/webserver/tutorial/src/main/java/io/helidon/examples/webserver/tutorial/CommentWriter.java b/examples/webserver/tutorial/src/main/java/io/helidon/examples/webserver/tutorial/CommentWriter.java deleted file mode 100644 index 8131d68812f..00000000000 --- a/examples/webserver/tutorial/src/main/java/io/helidon/examples/webserver/tutorial/CommentWriter.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2023 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.webserver.tutorial; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.UncheckedIOException; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.stream.Collectors; - -import io.helidon.common.GenericType; -import io.helidon.http.Headers; -import io.helidon.http.HttpMediaType; -import io.helidon.http.WritableHeaders; -import io.helidon.http.media.EntityWriter; - -class CommentWriter implements EntityWriter> { - - @Override - public void write(GenericType> type, - List comments, - OutputStream os, - Headers requestHeaders, - WritableHeaders responseHeaders) { - - write(comments, os, responseHeaders); - } - - @Override - public void write(GenericType> type, - List comments, - OutputStream os, - WritableHeaders headers) { - - write(comments, os, headers); - } - - private void write(List comments, OutputStream os, Headers headers) { - String str = comments.stream() - .map(Comment::toString) - .collect(Collectors.joining("\n")); - - Charset charset = headers.contentType() - .flatMap(HttpMediaType::charset) - .map(Charset::forName) - .orElse(StandardCharsets.UTF_8); - - try { - os.write(str.getBytes(charset)); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } -} diff --git a/examples/webserver/tutorial/src/main/java/io/helidon/examples/webserver/tutorial/Main.java b/examples/webserver/tutorial/src/main/java/io/helidon/examples/webserver/tutorial/Main.java deleted file mode 100644 index dde4a59c821..00000000000 --- a/examples/webserver/tutorial/src/main/java/io/helidon/examples/webserver/tutorial/Main.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.webserver.tutorial; - -import io.helidon.http.HttpMediaTypes; -import io.helidon.http.media.MediaContext; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.http.HttpRouting; - -/** - * Application java main class. - * - *

        The TUTORIAL application demonstrates various WebServer use cases together and in its complexity. - *

        It also serves web server tutorial articles composed of live examples. - */ -public final class Main { - - private Main() { - } - - /** - * Set up the routing. - * - * @param routing routing builder - */ - static void routing(HttpRouting.Builder routing) { - routing.any(new UserFilter()) - .register("/article", new CommentService()) - .post("/mgmt/shutdown", (req, res) -> { - res.headers().contentType(HttpMediaTypes.PLAINTEXT_UTF_8); - res.send("Shutting down TUTORIAL server. Good bye!\n"); - req.context() - .get(WebServer.class) - .orElseThrow() - .stop(); - }); - } - - /** - * Set up the server. - * - * @param server server builder - */ - static void setup(WebServerConfig.Builder server) { - server.routing(Main::routing) - .contentEncoding(encoding -> encoding.addContentEncoding(new UpperXEncodingProvider())) - .mediaContext(MediaContext.builder() - .addMediaSupport(new CommentSupport()) - .build()); - } - - /** - * A java main class. - * - * @param args command line arguments. - */ - public static void main(String[] args) { - // Create a web server instance - int port = 8080; - if (args.length > 0) { - try { - port = Integer.parseInt(args[0]); - } catch (NumberFormatException nfe) { - port = 0; - } - } - - WebServerConfig.Builder builder = WebServer.builder().port(port); - setup(builder); - WebServer server = builder.build().start(); - server.context().register(server); - - System.out.printf(""" - TUTORIAL server is up! http://localhost:%1$d" - Call POST on 'http://localhost:%1$d/mgmt/shutdown' to STOP the server! - """, server.port()); - } -} diff --git a/examples/webserver/tutorial/src/main/java/io/helidon/examples/webserver/tutorial/UpperXEncodingProvider.java b/examples/webserver/tutorial/src/main/java/io/helidon/examples/webserver/tutorial/UpperXEncodingProvider.java deleted file mode 100644 index e83de78ad0c..00000000000 --- a/examples/webserver/tutorial/src/main/java/io/helidon/examples/webserver/tutorial/UpperXEncodingProvider.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.webserver.tutorial; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Set; - -import io.helidon.http.encoding.ContentDecoder; -import io.helidon.http.encoding.ContentEncoder; -import io.helidon.http.encoding.ContentEncoding; - -/** - * All 'x' must be upper case. - *

        - * This is a naive implementation. - */ -public final class UpperXEncodingProvider implements ContentEncoding { - - @Override - public Set ids() { - return Set.of("upper-x"); - } - - @Override - public boolean supportsEncoding() { - return false; - } - - @Override - public boolean supportsDecoding() { - return true; - } - - @Override - public ContentDecoder decoder() { - return UpperXInputStream::new; - } - - @Override - public ContentEncoder encoder() { - return ContentEncoder.NO_OP; - } - - @Override - public String name() { - return "upper-x"; - } - - @Override - public String type() { - return "upper-x"; - } - - /** - * All 'x' must be upper case. - *

        - * This is a naive implementation. - */ - static final class UpperXInputStream extends FilterInputStream { - - UpperXInputStream(InputStream is) { - super(is); - } - - @Override - public int read() throws IOException { - int c = super.read(); - return c == 'x' ? 'X' : c; - } - } -} diff --git a/examples/webserver/tutorial/src/main/java/io/helidon/examples/webserver/tutorial/User.java b/examples/webserver/tutorial/src/main/java/io/helidon/examples/webserver/tutorial/User.java deleted file mode 100644 index 90960894f4a..00000000000 --- a/examples/webserver/tutorial/src/main/java/io/helidon/examples/webserver/tutorial/User.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.webserver.tutorial; - -import io.helidon.webserver.http.HttpRouting; - -/** - * Represents an immutable user. - * - *

        {@link UserFilter} can be registered on Web Server {@link HttpRouting Routing} to provide valid {@link User} - * instance on the request context. - */ -public final class User { - - /** - * Represents an anonymous user. - */ - public static final User ANONYMOUS = new User(); - - private final boolean authenticated; - private final String alias; - private final boolean anonymous; - - /** - * Creates new instance non-anonymous user. - * - * @param authenticated an authenticated is {@code true} if this user identity was validated - * @param alias an alias represents the name of the user which is visible for others - */ - User(boolean authenticated, String alias) { - this.authenticated = authenticated; - this.alias = alias; - this.anonymous = false; - } - - /** - * Creates an unauthenticated user. - * - * @param alias an alias represents the name of the user which is visible for others - */ - User(String alias) { - this(false, alias); - } - - /** - * Creates an anonymous user instance. - */ - private User() { - this.anonymous = true; - this.authenticated = false; - this.alias = "anonymous"; - } - - /** - * Indicate if this user identity was validated. - * - * @return {@code true} if validated - */ - public boolean isAuthenticated() { - return authenticated; - } - - /** - * Get the name of the user which is visible for others. - * - * @return alias - */ - public String alias() { - return alias; - } - - /** - * Indicate if this user is anonymous. - * - * @return {@code true} if anonymous - */ - public boolean isAnonymous() { - return anonymous; - } -} diff --git a/examples/webserver/tutorial/src/main/java/io/helidon/examples/webserver/tutorial/UserFilter.java b/examples/webserver/tutorial/src/main/java/io/helidon/examples/webserver/tutorial/UserFilter.java deleted file mode 100644 index 33e930fc94e..00000000000 --- a/examples/webserver/tutorial/src/main/java/io/helidon/examples/webserver/tutorial/UserFilter.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.webserver.tutorial; - -import io.helidon.webserver.http.Handler; -import io.helidon.webserver.http.HttpRouting; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -/** - * If used as a {@link HttpRouting} {@link Handler} then assign valid {@link User} instance on the request - * {@link io.helidon.common.context.Context context}. - */ -public class UserFilter implements Handler { - - @Override - public void handle(ServerRequest req, ServerResponse res) { - // Register as a supplier. - // Thanks to it, user instance is resolved ONLY if it is requested in downstream handlers. - req.context().supply(User.class, - () -> req.headers() - .cookies() - .first("Unauthenticated-User-Alias") - .map(User::new) - .orElse(User.ANONYMOUS)); - res.next(); - } -} diff --git a/examples/webserver/tutorial/src/main/java/io/helidon/examples/webserver/tutorial/package-info.java b/examples/webserver/tutorial/src/main/java/io/helidon/examples/webserver/tutorial/package-info.java deleted file mode 100644 index 46501698c6c..00000000000 --- a/examples/webserver/tutorial/src/main/java/io/helidon/examples/webserver/tutorial/package-info.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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. - */ - -/** - * A tutorial documentation server. It serves various tutorial articles designed based on project examples. - * - *

        It is also a complex example demonstrating various web server features. - */ -package io.helidon.examples.webserver.tutorial; diff --git a/examples/webserver/tutorial/src/main/resources/logging.properties b/examples/webserver/tutorial/src/main/resources/logging.properties deleted file mode 100644 index ecfe90ddb2e..00000000000 --- a/examples/webserver/tutorial/src/main/resources/logging.properties +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright (c) 2018, 2024 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 - -# Send messages to the console -handlers=io.helidon.logging.jul.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 diff --git a/examples/webserver/tutorial/src/test/java/io/helidon/examples/webserver/tutorial/CommentServiceTest.java b/examples/webserver/tutorial/src/test/java/io/helidon/examples/webserver/tutorial/CommentServiceTest.java deleted file mode 100644 index 93d55859e20..00000000000 --- a/examples/webserver/tutorial/src/test/java/io/helidon/examples/webserver/tutorial/CommentServiceTest.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.webserver.tutorial; - -import io.helidon.common.media.type.MediaTypes; -import io.helidon.http.Status; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.collection.IsCollectionWithSize.hasSize; -import static org.hamcrest.collection.IsEmptyCollection.empty; - -/** - * Tests {@link CommentService}. - */ -@ServerTest -class CommentServiceTest { - - private final Http1Client client; - - CommentServiceTest(Http1Client client) { - this.client = client; - } - - @SetUpServer - static void setup(WebServerConfig.Builder server) { - Main.setup(server); - } - - @Test - void addAndGetComments() { - CommentService service = new CommentService(); - assertThat(service.getComments("one"), empty()); - assertThat(service.getComments("two"), empty()); - service.addComment("one", null, "aaa"); - assertThat(service.getComments("one"), hasSize(1)); - assertThat(service.getComments("two"), empty()); - service.addComment("one", null, "bbb"); - assertThat(service.getComments("one"), hasSize(2)); - assertThat(service.getComments("two"), empty()); - service.addComment("two", null, "bbb"); - assertThat(service.getComments("one"), hasSize(2)); - assertThat(service.getComments("two"), hasSize(1)); - } - - @Test - void testRouting() { - try (Http1ClientResponse response = client.get("/article/one").request()) { - assertThat(response.status(), is(Status.OK_200)); - } - - // Add first comment - try (Http1ClientResponse response = client.post("/article/one") - .contentType(MediaTypes.TEXT_PLAIN) - .submit("aaa")) { - assertThat(response.status(), is(Status.OK_200)); - } - - try (Http1ClientResponse response = client.get("/article/one").request()) { - assertThat(response.status(), is(Status.OK_200)); - assertThat(response.entity().as(String.class), is("anonymous: aaa")); - } - - - // Add second comment - try (Http1ClientResponse response = client.post("/article/one") - .contentType(MediaTypes.TEXT_PLAIN) - .submit("bbb")) { - assertThat(response.status(), is(Status.OK_200)); - } - - try (Http1ClientResponse response = client.get("/article/one").request()) { - assertThat(response.status(), is(Status.OK_200)); - assertThat(response.entity().as(String.class), is("anonymous: aaa\nanonymous: bbb")); - } - } -} diff --git a/examples/webserver/tutorial/src/test/java/io/helidon/examples/webserver/tutorial/MainTest.java b/examples/webserver/tutorial/src/test/java/io/helidon/examples/webserver/tutorial/MainTest.java deleted file mode 100644 index d084d131598..00000000000 --- a/examples/webserver/tutorial/src/test/java/io/helidon/examples/webserver/tutorial/MainTest.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.webserver.tutorial; - -import io.helidon.http.Status; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Tests {@link Main}. - */ -@ServerTest -public class MainTest { - - private final WebServer server; - private final Http1Client client; - - public MainTest(WebServer server, Http1Client client) { - server.context().register(server); - this.server = server; - this.client = client; - } - - @SetUpServer - static void setup(WebServerConfig.Builder server) { - Main.setup(server); - } - - @Test - public void testShutDown() throws InterruptedException { - try (Http1ClientResponse response = client.post("/mgmt/shutdown").request()) { - assertThat(response.status(), is(Status.OK_200)); - } - // there may be some delay between the request being completed, and the server shutting down - // let's give it a second to shut down, then fail - for (int i = 0; i < 10; i++) { - if (server.isRunning()) { - Thread.sleep(100); - } else { - break; - } - } - assertThat(server.isRunning(), is(false)); - } -} diff --git a/examples/webserver/tutorial/src/test/java/io/helidon/examples/webserver/tutorial/UserFilterTest.java b/examples/webserver/tutorial/src/test/java/io/helidon/examples/webserver/tutorial/UserFilterTest.java deleted file mode 100644 index 95be71d314b..00000000000 --- a/examples/webserver/tutorial/src/test/java/io/helidon/examples/webserver/tutorial/UserFilterTest.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2017, 2023 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.webserver.tutorial; - -import io.helidon.http.HeaderNames; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.http.HttpRouting; -import io.helidon.webserver.testing.junit5.DirectClient; -import io.helidon.webserver.testing.junit5.RoutingTest; -import io.helidon.webserver.testing.junit5.SetUpRoute; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Tests {@link UserFilter}. - */ -@RoutingTest -public class UserFilterTest { - - private final DirectClient client; - - UserFilterTest(DirectClient client) { - this.client = client; - } - - @SetUpRoute - static void setup(HttpRouting.Builder routing) { - routing.any(new UserFilter()) - .any((req, res) -> res.send(req.context() - .get(User.class) - .orElse(User.ANONYMOUS) - .alias())); - } - - @Test - public void filter() { - try (Http1ClientResponse response = client.get().request()) { - assertThat(response.entity().as(String.class), is("anonymous")); - } - - try (Http1ClientResponse response = client.get() - .header(HeaderNames.COOKIE, "Unauthenticated-User-Alias=Foo") - .request()) { - assertThat(response.entity().as(String.class), is("Foo")); - } - } -} diff --git a/examples/webserver/websocket/README.md b/examples/webserver/websocket/README.md deleted file mode 100644 index 6a1c48eb4e1..00000000000 --- a/examples/webserver/websocket/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# WebSocket Example - -This application demonstrates use of websockets and REST. - -## Build and run - -```shell -mvn package -java -jar target/helidon-examples-webserver-websocket.jar -``` - -Open http://localhost:8080/web/index.html in your browser. -`` diff --git a/examples/webserver/websocket/pom.xml b/examples/webserver/websocket/pom.xml deleted file mode 100644 index f27badd14d8..00000000000 --- a/examples/webserver/websocket/pom.xml +++ /dev/null @@ -1,100 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../applications/se/pom.xml - - io.helidon.examples.webserver - helidon-examples-webserver-websocket - Helidon Examples WebServer WebSocket - - - Application demonstrates the use of websockets and REST. - - - - io.helidon.examples.webserver.websocket.Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver - helidon-webserver-static-content - - - io.helidon.webserver - helidon-webserver-websocket - - - io.helidon.logging - helidon-logging-jul - runtime - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5 - test - - - io.helidon.webserver.testing.junit5 - helidon-webserver-testing-junit5-websocket - test - - - io.helidon.webclient - helidon-webclient-websocket - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/examples/webserver/websocket/src/main/java/io/helidon/examples/webserver/websocket/Main.java b/examples/webserver/websocket/src/main/java/io/helidon/examples/webserver/websocket/Main.java deleted file mode 100644 index d2fec029780..00000000000 --- a/examples/webserver/websocket/src/main/java/io/helidon/examples/webserver/websocket/Main.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.webserver.websocket; - -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.staticcontent.StaticContentService; -import io.helidon.webserver.websocket.WsRouting; - -/** - * Application demonstrates combination of websocket and REST. - */ -public class Main { - - private Main() { - } - - static void setup(WebServerConfig.Builder server) { - StaticContentService staticContent = StaticContentService.builder("/WEB") - .welcomeFileName("index.html") - .build(); - MessageQueueService messageQueueService = new MessageQueueService(); - server.routing(routing -> routing - .register("/web", staticContent) - .register("/rest", messageQueueService)) - .addRouting(WsRouting.builder() - .endpoint("/websocket/board", new MessageBoardEndpoint())); - } - - /** - * A java main class. - * - * @param args command line arguments. - */ - public static void main(String[] args) { - WebServerConfig.Builder builder = WebServer.builder().port(8080); - setup(builder); - WebServer server = builder.build().start(); - System.out.println("WEB server is up! http://localhost:" + server.port() + "/web"); - } -} diff --git a/examples/webserver/websocket/src/main/java/io/helidon/examples/webserver/websocket/MessageBoardEndpoint.java b/examples/webserver/websocket/src/main/java/io/helidon/examples/webserver/websocket/MessageBoardEndpoint.java deleted file mode 100644 index 7600bee0eaa..00000000000 --- a/examples/webserver/websocket/src/main/java/io/helidon/examples/webserver/websocket/MessageBoardEndpoint.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2020, 2024 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.webserver.websocket; - -import io.helidon.websocket.WsListener; -import io.helidon.websocket.WsSession; - -/** - * Class MessageBoardEndpoint. - */ -public class MessageBoardEndpoint implements WsListener { - private final MessageQueue messageQueue = MessageQueue.instance(); - - @Override - public void onMessage(WsSession session, String text, boolean last) { - // Send all messages in the queue - if (text.equals("SEND")) { - while (!messageQueue.isEmpty()) { - session.send(messageQueue.pop(), last); - } - } - } -} diff --git a/examples/webserver/websocket/src/main/java/io/helidon/examples/webserver/websocket/MessageQueue.java b/examples/webserver/websocket/src/main/java/io/helidon/examples/webserver/websocket/MessageQueue.java deleted file mode 100644 index 60d5b448de0..00000000000 --- a/examples/webserver/websocket/src/main/java/io/helidon/examples/webserver/websocket/MessageQueue.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.webserver.websocket; - -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; - -/** - * Class MessageQueue. - */ -public class MessageQueue { - - private static final MessageQueue INSTANCE = new MessageQueue(); - - private Queue queue = new ConcurrentLinkedQueue<>(); - - /** - * Return singleton instance of this class. - * - * @return Singleton. - */ - public static MessageQueue instance() { - return INSTANCE; - } - - private MessageQueue() { - } - - /** - * Push string on stack. - * - * @param s String to push. - */ - public void push(String s) { - queue.add(s); - } - - /** - * Pop string from stack. - * - * @return The string or {@code null}. - */ - public String pop() { - return queue.poll(); - } - - /** - * Check if stack is empty. - * - * @return Outcome of test. - */ - public boolean isEmpty() { - return queue.isEmpty(); - } - - /** - * Peek at stack without changing it. - * - * @return String peeked or {@code null}. - */ - public String peek() { - return queue.peek(); - } -} diff --git a/examples/webserver/websocket/src/main/java/io/helidon/examples/webserver/websocket/MessageQueueService.java b/examples/webserver/websocket/src/main/java/io/helidon/examples/webserver/websocket/MessageQueueService.java deleted file mode 100644 index 758d228d606..00000000000 --- a/examples/webserver/websocket/src/main/java/io/helidon/examples/webserver/websocket/MessageQueueService.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.webserver.websocket; - -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -/** - * Class MessageQueueResource. - */ -public class MessageQueueService implements HttpService { - - private final MessageQueue messageQueue = MessageQueue.instance(); - - @Override - public void routing(HttpRules routingRules) { - routingRules.post("/board", this::handlePost); - } - - private void handlePost(ServerRequest request, ServerResponse response) { - messageQueue.push(request.content().as(String.class)); - response.status(204).send(); - } -} diff --git a/examples/webserver/websocket/src/main/java/io/helidon/examples/webserver/websocket/package-info.java b/examples/webserver/websocket/src/main/java/io/helidon/examples/webserver/websocket/package-info.java deleted file mode 100644 index e8e828b8379..00000000000 --- a/examples/webserver/websocket/src/main/java/io/helidon/examples/webserver/websocket/package-info.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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. - */ - -/** - * Application demonstrates combination of the websocket and REST. - * - *

        - * Start with {@link io.helidon.examples.webserver.websocket.Main} class. - * - * @see io.helidon.examples.webserver.websocket.Main - */ -package io.helidon.examples.webserver.websocket; diff --git a/examples/webserver/websocket/src/main/resources/WEB/index.html b/examples/webserver/websocket/src/main/resources/WEB/index.html deleted file mode 100644 index f5ecf5c8b3f..00000000000 --- a/examples/webserver/websocket/src/main/resources/WEB/index.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - - -

        -
        -

        -

        - -

        -

        - -

        -

        -

        History

        -
        -
        - - diff --git a/examples/webserver/websocket/src/main/resources/logging.properties b/examples/webserver/websocket/src/main/resources/logging.properties deleted file mode 100644 index ddbc8d6521d..00000000000 --- a/examples/webserver/websocket/src/main/resources/logging.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2020, 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. -# - -handlers=io.helidon.logging.jul.HelidonConsoleHandler -java.util.logging.SimpleFormatter.format=[%1$tc] %4$s: %2$s - %5$s %6$s%n -.level=INFO -io.helidon.microprofile.server.level=INFO diff --git a/examples/webserver/websocket/src/test/java/io/helidon/examples/webserver/websocket/MessageBoardTest.java b/examples/webserver/websocket/src/test/java/io/helidon/examples/webserver/websocket/MessageBoardTest.java deleted file mode 100644 index 998f0e8be61..00000000000 --- a/examples/webserver/websocket/src/test/java/io/helidon/examples/webserver/websocket/MessageBoardTest.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2020, 2024 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.webserver.websocket; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.logging.Logger; - -import io.helidon.http.Status; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webclient.websocket.WsClient; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.testing.junit5.ServerTest; -import io.helidon.webserver.testing.junit5.SetUpServer; -import io.helidon.websocket.WsCloseCodes; -import io.helidon.websocket.WsListener; -import io.helidon.websocket.WsSession; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Class MessageBoardTest. - */ -@ServerTest -public class MessageBoardTest { - private static final Logger LOGGER = Logger.getLogger(MessageBoardTest.class.getName()); - - private static final String[] MESSAGES = {"Whisky", "Tango", "Foxtrot"}; - private final WsClient wsClient; - private final Http1Client client; - - MessageBoardTest(Http1Client client, WsClient wsClient) { - this.client = client; - this.wsClient = wsClient; - } - - @SetUpServer - static void setup(WebServerConfig.Builder server) { - Main.setup(server); - } - - @Test - public void testBoard() throws InterruptedException { - // Post messages using REST resource - for (String message : MESSAGES) { - try (Http1ClientResponse response = client.post("/rest/board").submit(message)) { - assertThat(response.status(), is(Status.NO_CONTENT_204)); - LOGGER.info("Posting message '" + message + "'"); - } - } - - // Now connect to message board using WS and them back - - CountDownLatch messageLatch = new CountDownLatch(MESSAGES.length); - - wsClient.connect("/websocket/board", new WsListener() { - @Override - public void onMessage(WsSession session, String text, boolean last) { - LOGGER.info("Client OnMessage called '" + text + "'"); - messageLatch.countDown(); - if (messageLatch.getCount() == 0) { - session.close(WsCloseCodes.NORMAL_CLOSE, "Bye!"); - } - } - - @Override - public void onOpen(WsSession session) { - session.send("SEND", false); - } - }); - - // Wait until all messages are received - assertThat(messageLatch.await(1000000, TimeUnit.SECONDS), is(true)); - } -} diff --git a/pom.xml b/pom.xml index 9cf02ac252c..8fb000087c2 100644 --- a/pom.xml +++ b/pom.xml @@ -1319,7 +1319,7 @@ examples - examples + helidon-examples From 30088db7c4053f279848ea5f57efd72b3c56ed21 Mon Sep 17 00:00:00 2001 From: Joe DiPol Date: Fri, 2 Aug 2024 15:10:59 -0700 Subject: [PATCH 26/37] 4.x : Updates links to examples that are in documentation to point to the `helidon-examples` repository. (#9094) * Update links to example source * Remove statement of Java version from neo4j docs * Add README for now empty examples directory --- docs/src/main/asciidoc/includes/attributes.adoc | 4 +++- docs/src/main/asciidoc/includes/guides/gradle-build.adoc | 4 ++-- docs/src/main/asciidoc/includes/guides/maven-build.adoc | 2 +- .../main/asciidoc/includes/metrics/metrics-shared.adoc | 4 ++-- .../main/asciidoc/includes/metrics/micrometer-shared.adoc | 4 ++-- .../includes/metrics/prometheus-exemplar-support.adoc | 2 +- docs/src/main/asciidoc/includes/openapi/openapi.adoc | 2 +- .../main/asciidoc/includes/security/providers/abac.adoc | 2 +- .../includes/security/providers/google-login.adoc | 2 +- .../includes/security/providers/http-basic-auth.adoc | 2 +- .../includes/security/providers/http-signatures.adoc | 2 +- .../includes/security/providers/idcs-role-mapper.adoc | 2 +- .../main/asciidoc/includes/security/providers/jwt.adoc | 4 ++-- .../main/asciidoc/includes/security/providers/oidc.adoc | 2 +- .../includes/security/providers/provider-template.adoc | 4 ++-- docs/src/main/asciidoc/mp/beanvalidation.adoc | 2 +- docs/src/main/asciidoc/mp/cors/cors.adoc | 4 ++-- docs/src/main/asciidoc/mp/graphql.adoc | 4 ++-- docs/src/main/asciidoc/mp/health.adoc | 4 ++-- docs/src/main/asciidoc/mp/integrations/hcv.adoc | 2 +- docs/src/main/asciidoc/mp/integrations/neo4j.adoc | 2 +- docs/src/main/asciidoc/mp/integrations/oci.adoc | 2 +- docs/src/main/asciidoc/mp/metrics/metrics.adoc | 2 +- docs/src/main/asciidoc/mp/openapi/openapi.adoc | 4 ++-- docs/src/main/asciidoc/mp/persistence.adoc | 2 +- docs/src/main/asciidoc/mp/reactivemessaging/kafka.adoc | 2 +- docs/src/main/asciidoc/mp/telemetry.adoc | 2 +- docs/src/main/asciidoc/mp/websocket.adoc | 2 +- docs/src/main/asciidoc/se/cors.adoc | 4 ++-- docs/src/main/asciidoc/se/dbclient.adoc | 2 +- docs/src/main/asciidoc/se/grpc/server.adoc | 2 +- docs/src/main/asciidoc/se/guides/dbclient.adoc | 2 +- docs/src/main/asciidoc/se/guides/upgrade_4x.adoc | 2 +- docs/src/main/asciidoc/se/integrations/hcv.adoc | 2 +- docs/src/main/asciidoc/se/integrations/neo4j.adoc | 6 +++--- docs/src/main/asciidoc/se/integrations/oci.adoc | 2 +- docs/src/main/asciidoc/se/openapi/openapi.adoc | 2 +- docs/src/main/asciidoc/se/reactive-messaging.adoc | 6 +++--- docs/src/main/asciidoc/se/websocket.adoc | 2 +- examples/README.md | 8 ++++++++ 40 files changed, 63 insertions(+), 53 deletions(-) create mode 100644 examples/README.md diff --git a/docs/src/main/asciidoc/includes/attributes.adoc b/docs/src/main/asciidoc/includes/attributes.adoc index 3a2ce86d960..cc1d001d9e9 100644 --- a/docs/src/main/asciidoc/includes/attributes.adoc +++ b/docs/src/main/asciidoc/includes/attributes.adoc @@ -24,16 +24,18 @@ ifndef::attributes-included[] :imagesdir: {rootdir}/images :helidon-version: 4.1.0-SNAPSHOT -:helidon-version-is-release: true +:helidon-version-is-release: false :sourcedir: {rootdir}/../java/io/helidon/docs ifeval::["{helidon-version-is-release}" != "true"] :helidon-github-tree-url: https://github.com/oracle/helidon/tree/main +:helidon-github-examples-url: https://github.com/helidon-io/helidon-examples/tree/helidon-4.x/examples endif::[] ifeval::["{helidon-version-is-release}" == "true"] :helidon-github-tree-url: https://github.com/oracle/helidon/tree/{helidon-version} +:helidon-github-examples-url: https://github.com/helidon-io/helidon-examples/tree/{helidon-version}/examples endif::[] // versions diff --git a/docs/src/main/asciidoc/includes/guides/gradle-build.adoc b/docs/src/main/asciidoc/includes/guides/gradle-build.adoc index 0b5e014e1ea..28ee0b215bd 100644 --- a/docs/src/main/asciidoc/includes/guides/gradle-build.adoc +++ b/docs/src/main/asciidoc/includes/guides/gradle-build.adoc @@ -1,6 +1,6 @@ /////////////////////////////////////////////////////////////////////////////// - Copyright (c) 2020, 2023 Oracle and/or its affiliates. + Copyright (c) 2020, 2024 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. @@ -26,7 +26,7 @@ with a Gradle project. Gradle 8.4+ is required to build Helidon 4 projects. == Gradle Example The Helidon -link:{helidon-github-tree-url}/examples/quickstarts/helidon-quickstart-{flavor-lc}[Quickstart Example] +link:{helidon-github-examples-url}/quickstarts/helidon-quickstart-{flavor-lc}[Quickstart Example] contains a `build.gradle` file that you can use as an example for building your Helidon application using Gradle. diff --git a/docs/src/main/asciidoc/includes/guides/maven-build.adoc b/docs/src/main/asciidoc/includes/guides/maven-build.adoc index 05b050d3537..300e29c8e0a 100644 --- a/docs/src/main/asciidoc/includes/guides/maven-build.adoc +++ b/docs/src/main/asciidoc/includes/guides/maven-build.adoc @@ -37,7 +37,7 @@ use a Helidon application POM as their parent. This parent POM provides the foll Helidon application. If you want to use your own parent POM, then take a look at the -link:{helidon-github-tree-url}/examples/quickstarts/helidon-standalone-quickstart-{flavor-lc}[standalone quickstart example]. +link:{helidon-github-examples-url}/quickstarts/helidon-standalone-quickstart-{flavor-lc}[standalone quickstart example]. This example has a standalone POM that you can pattern your own application POM after. For more details on Helidon application POMs see the diff --git a/docs/src/main/asciidoc/includes/metrics/metrics-shared.adoc b/docs/src/main/asciidoc/includes/metrics/metrics-shared.adoc index 1b968b4487d..f341dbe2c37 100644 --- a/docs/src/main/asciidoc/includes/metrics/metrics-shared.adoc +++ b/docs/src/main/asciidoc/includes/metrics/metrics-shared.adoc @@ -215,11 +215,11 @@ Once it has a reference to a `MetricRegistry` your code can use the reference to // tag::example-apps[] Helidon {flavor-uc} includes several pre-written example applications illustrating aspects of metrics: -* link:{helidon-github-tree-url}/examples/metrics/filtering/{flavor-lc}[Enabling/disabling {metrics}] using +* link:{helidon-github-examples-url}/metrics/filtering/{flavor-lc}[Enabling/disabling {metrics}] using ifdef::se-flavor[`MetricsObserver` and `MetricsConfig`] ifdef::mp-flavor[configuration] ifdef::se-flavor[] -* link:{helidon-github-tree-url}/examples/metrics/kpi[Controlling key performance indicator metrics] using configuration and `KeyPerformanceIndicatorMetricsSettings`. +* link:{helidon-github-examples-url}/metrics/kpi[Controlling key performance indicator metrics] using configuration and `KeyPerformanceIndicatorMetricsSettings`. endif::[] // end::example-apps[] diff --git a/docs/src/main/asciidoc/includes/metrics/micrometer-shared.adoc b/docs/src/main/asciidoc/includes/metrics/micrometer-shared.adoc index 10857a98d71..14c8a293186 100644 --- a/docs/src/main/asciidoc/includes/metrics/micrometer-shared.adoc +++ b/docs/src/main/asciidoc/includes/metrics/micrometer-shared.adoc @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// - Copyright (c) 2021, 2023 Oracle and/or its affiliates. + Copyright (c) 2021, 2024 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. @@ -187,7 +187,7 @@ can create, look up, and update metrics programmatically using the Micrometer `M // end::use-micrometer-api[] // tag::example-apps[] -Helidon {flavor-uc} includes an link:{helidon-github-tree-url}/examples/integrations/micrometer/{flavor-lc}[example application] which uses Micrometer support. +Helidon {flavor-uc} includes an link:{helidon-github-examples-url}/integrations/micrometer/{flavor-lc}[example application] which uses Micrometer support. // end::example-apps[] // end::all-micrometer[] diff --git a/docs/src/main/asciidoc/includes/metrics/prometheus-exemplar-support.adoc b/docs/src/main/asciidoc/includes/metrics/prometheus-exemplar-support.adoc index 5c1c042c728..d6abdc43029 100644 --- a/docs/src/main/asciidoc/includes/metrics/prometheus-exemplar-support.adoc +++ b/docs/src/main/asciidoc/includes/metrics/prometheus-exemplar-support.adoc @@ -108,7 +108,7 @@ But some consumers, such as trace collectors and their UIs, understand the exemp == Examples ifdef::se-flavor[] -Helidon includes an link:{helidon-github-tree-url}/examples/metrics/exemplar[example application], based on the QuickStart application, which illustrates exemplar support. +Helidon includes an link:{helidon-github-examples-url}/metrics/exemplar[example application], based on the QuickStart application, which illustrates exemplar support. endif::[] Once you enable exemplar support you can see the exemplars in the metrics output. diff --git a/docs/src/main/asciidoc/includes/openapi/openapi.adoc b/docs/src/main/asciidoc/includes/openapi/openapi.adoc index 4e345fc3a5c..e0d04247af0 100644 --- a/docs/src/main/asciidoc/includes/openapi/openapi.adoc +++ b/docs/src/main/asciidoc/includes/openapi/openapi.adoc @@ -98,7 +98,7 @@ You can also define any request parameters the endpoint expects, although this endpoint uses none. This excerpt shows only a few annotations for illustration. The -link:{helidon-github-tree-url}/examples/microprofile/openapi-basic[Helidon MP OpenAPI example] illustrates more, +link:{helidon-github-examples-url}/microprofile/openapi[Helidon MP OpenAPI example] illustrates more, and the link:{microprofile-open-api-spec-url}[MicroProfile OpenAPI spec] describes them all. ===== A static OpenAPI file diff --git a/docs/src/main/asciidoc/includes/security/providers/abac.adoc b/docs/src/main/asciidoc/includes/security/providers/abac.adoc index 8d689b36d9b..5a1f0820096 100644 --- a/docs/src/main/asciidoc/includes/security/providers/abac.adoc +++ b/docs/src/main/asciidoc/includes/security/providers/abac.adoc @@ -44,7 +44,7 @@ include::{rootdir}/config/io_helidon_security_providers_abac_AbacProvider.adoc[l ==== Example code -See the link:{helidon-github-tree-url}/examples/security/attribute-based-access-control[example] on GitHub. +See the link:{helidon-github-examples-url}/security/attribute-based-access-control[example] on GitHub. [source,yaml] .Configuration example diff --git a/docs/src/main/asciidoc/includes/security/providers/google-login.adoc b/docs/src/main/asciidoc/includes/security/providers/google-login.adoc index c6cdc8bf003..7f8edb32f29 100644 --- a/docs/src/main/asciidoc/includes/security/providers/google-login.adoc +++ b/docs/src/main/asciidoc/includes/security/providers/google-login.adoc @@ -42,7 +42,7 @@ include::{rootdir}/config/io_helidon_security_providers_google_login_GoogleToken ==== Example code -See the link:{helidon-github-tree-url}/examples/security/google-login[example] on GitHub. +See the link:{helidon-github-examples-url}/security/google-login[example] on GitHub. [source,yaml] .Configuration example diff --git a/docs/src/main/asciidoc/includes/security/providers/http-basic-auth.adoc b/docs/src/main/asciidoc/includes/security/providers/http-basic-auth.adoc index 0579052287e..fee3791f349 100644 --- a/docs/src/main/asciidoc/includes/security/providers/http-basic-auth.adoc +++ b/docs/src/main/asciidoc/includes/security/providers/http-basic-auth.adoc @@ -42,7 +42,7 @@ include::{rootdir}/config/io_helidon_security_providers_httpauth_HttpBasicAuthPr ==== Example code -See the link:{helidon-github-tree-url}/examples/security/outbound-override[example] on GitHub. +See the link:{helidon-github-examples-url}/security/outbound-override[example] on GitHub. [source,yaml] .Configuration example diff --git a/docs/src/main/asciidoc/includes/security/providers/http-signatures.adoc b/docs/src/main/asciidoc/includes/security/providers/http-signatures.adoc index e6b4c0ba01f..c0a0c1f3ab7 100644 --- a/docs/src/main/asciidoc/includes/security/providers/http-signatures.adoc +++ b/docs/src/main/asciidoc/includes/security/providers/http-signatures.adoc @@ -43,7 +43,7 @@ include::{rootdir}/config/io_helidon_security_providers_httpsign_HttpSignProvide ==== Example code -See the link:{helidon-github-tree-url}/examples/security/webserver-signatures[example] on GitHub. +See the link:{helidon-github-examples-url}/security/webserver-signatures[example] on GitHub. [source,yaml] .Configuration example diff --git a/docs/src/main/asciidoc/includes/security/providers/idcs-role-mapper.adoc b/docs/src/main/asciidoc/includes/security/providers/idcs-role-mapper.adoc index 3cc1b616b74..a769616a5c1 100644 --- a/docs/src/main/asciidoc/includes/security/providers/idcs-role-mapper.adoc +++ b/docs/src/main/asciidoc/includes/security/providers/idcs-role-mapper.adoc @@ -46,7 +46,7 @@ include::{rootdir}/config/io_helidon_security_providers_idcs_mapper_IdcsMtRoleMa ==== Example code -See the link:{helidon-github-tree-url}/examples/security/idcs-login/[example] on GitHub. +See the link:{helidon-github-examples-url}/security/idcs-login/[example] on GitHub. [source,yaml] .Configuration example diff --git a/docs/src/main/asciidoc/includes/security/providers/jwt.adoc b/docs/src/main/asciidoc/includes/security/providers/jwt.adoc index ec1c4dacdce..27fab7df16a 100644 --- a/docs/src/main/asciidoc/includes/security/providers/jwt.adoc +++ b/docs/src/main/asciidoc/includes/security/providers/jwt.adoc @@ -1,6 +1,6 @@ /////////////////////////////////////////////////////////////////////////////// - Copyright (c) 2020, 2023 Oracle and/or its affiliates. + Copyright (c) 2020, 2024 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. @@ -42,7 +42,7 @@ include::{rootdir}/config/io_helidon_security_providers_jwt_JwtProvider.adoc[lev ==== Example code -See the link:{helidon-github-tree-url}/examples/security/outbound-override[example] on GitHub. +See the link:{helidon-github-examples-url}/security/outbound-override[example] on GitHub. [source,yaml] .Configuration example diff --git a/docs/src/main/asciidoc/includes/security/providers/oidc.adoc b/docs/src/main/asciidoc/includes/security/providers/oidc.adoc index 3696452b3b5..412166afc52 100644 --- a/docs/src/main/asciidoc/includes/security/providers/oidc.adoc +++ b/docs/src/main/asciidoc/includes/security/providers/oidc.adoc @@ -26,7 +26,7 @@ ifndef::rootdir[:rootdir: {docdir}/../../..] include::{rootdir}/config/io_helidon_security_providers_oidc_OidcProvider.adoc[leveloffset=+2,tag=config] === Example code -See the link:{helidon-github-tree-url}/examples/security/idcs-login[example] on GitHub. +See the link:{helidon-github-examples-url}/security/idcs-login[example] on GitHub. [source,yaml] .Configuration example diff --git a/docs/src/main/asciidoc/includes/security/providers/provider-template.adoc b/docs/src/main/asciidoc/includes/security/providers/provider-template.adoc index 539ffa22ee8..30b22cd0587 100644 --- a/docs/src/main/asciidoc/includes/security/providers/provider-template.adoc +++ b/docs/src/main/asciidoc/includes/security/providers/provider-template.adoc @@ -1,6 +1,6 @@ /////////////////////////////////////////////////////////////////////////////// - Copyright (c) 2020, 2023 Oracle and/or its affiliates. + Copyright (c) 2020, 2024 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. @@ -48,7 +48,7 @@ provider-config-key ---- ==== Example code -See the link:{helidon-github-tree-url}/examples/security/[example] on GitHub. +See the link:{helidon-github-examples-url}/security/[example] on GitHub. [source,yaml] .Configuration example diff --git a/docs/src/main/asciidoc/mp/beanvalidation.adoc b/docs/src/main/asciidoc/mp/beanvalidation.adoc index 4ba5a3ccb6b..486e24c3b70 100644 --- a/docs/src/main/asciidoc/mp/beanvalidation.adoc +++ b/docs/src/main/asciidoc/mp/beanvalidation.adoc @@ -387,7 +387,7 @@ include::{sourcedir}/mp/BeanvalidationSnippets.java[tag=snippet_3, indent=0] + NOTE: `beans.xml` is required to identify beans and for bean validation to work properly. -Examples are available in link:{helidon-github-tree-url}/examples/microprofile/bean-validation[our official GitHub repository]. +Examples are available in link:{helidon-github-examples-url}/microprofile/bean-validation[our official GitHub repository]. == Additional Information diff --git a/docs/src/main/asciidoc/mp/cors/cors.adoc b/docs/src/main/asciidoc/mp/cors/cors.adoc index 8acc4094b8b..ae3ca85415f 100644 --- a/docs/src/main/asciidoc/mp/cors/cors.adoc +++ b/docs/src/main/asciidoc/mp/cors/cors.adoc @@ -135,12 +135,12 @@ include::{rootdir}/includes/cors.adoc[tag=cors-config-table] == Examples -The link:{helidon-github-tree-url}/examples/quickstarts/helidon-quickstart-mp[Helidon MP Quickstart application] allows users to: +The link:{helidon-github-examples-url}/quickstarts/helidon-quickstart-mp[Helidon MP Quickstart application] allows users to: * obtain greetings by sending `GET` requests to the `/greet` resource, and * change the greeting message by sending a `PUT` request to the `/greet/greeting` resource. -The link:{helidon-github-tree-url}/examples/microprofile/cors[Helidon MP CORS Example] shows the basic quickstart example enhanced for CORS. +The link:{helidon-github-examples-url}/microprofile/cors[Helidon MP CORS Example] shows the basic quickstart example enhanced for CORS. The discussion below describes the changes in the application which: diff --git a/docs/src/main/asciidoc/mp/graphql.adoc b/docs/src/main/asciidoc/mp/graphql.adoc index b2c8c853259..6c784ec7f1f 100644 --- a/docs/src/main/asciidoc/mp/graphql.adoc +++ b/docs/src/main/asciidoc/mp/graphql.adoc @@ -132,7 +132,7 @@ additional information on how to change the location of these resources. If you wish to use the link:https://github.com/graphql/graphiql[GraphQL UI] then please see the -link:{helidon-github-tree-url}/examples/microprofile/graphql[GraphQL MP Example]. +link:{helidon-github-examples-url}/microprofile/graphql[GraphQL MP Example]. == Configuration @@ -154,7 +154,7 @@ include::{rootdir}/includes/graphql.adoc[] == Examples For a complete example, see -link:{helidon-github-tree-url}/examples/microprofile/graphql[GraphQL MP Example]. +link:{helidon-github-examples-url}/microprofile/graphql[GraphQL MP Example]. == Additional Information diff --git a/docs/src/main/asciidoc/mp/health.adoc b/docs/src/main/asciidoc/mp/health.adoc index 1fe64f20518..16a4c9f768b 100644 --- a/docs/src/main/asciidoc/mp/health.adoc +++ b/docs/src/main/asciidoc/mp/health.adoc @@ -351,7 +351,7 @@ curl -v http://localhost:8080/health/ready } ---- -Full example code is available link:{helidon-github-tree-url}/examples/microprofile[here]. +Full example code is available link:{helidon-github-examples-url}/microprofile[here]. === Custom Startup Health Checks @@ -459,7 +459,7 @@ curl http://localhost:8080/health } ---- -Full example code is available link:{helidon-github-tree-url}/examples/microprofile[here]. +Full example code is available link:{helidon-github-examples-url}/microprofile[here]. == Reference diff --git a/docs/src/main/asciidoc/mp/integrations/hcv.adoc b/docs/src/main/asciidoc/mp/integrations/hcv.adoc index 735ffb5c1f0..bb72200a9c8 100644 --- a/docs/src/main/asciidoc/mp/integrations/hcv.adoc +++ b/docs/src/main/asciidoc/mp/integrations/hcv.adoc @@ -235,4 +235,4 @@ This will create a Vault docker image, run it in background and open it on `loca == References -* link:{helidon-github-tree-url}/examples/integrations/vault[Hashicorp Vault Usage Examples] +* link:{helidon-github-examples-url}/integrations/vault[Hashicorp Vault Usage Examples] diff --git a/docs/src/main/asciidoc/mp/integrations/neo4j.adoc b/docs/src/main/asciidoc/mp/integrations/neo4j.adoc index bba247dfd30..b1ccc716784 100644 --- a/docs/src/main/asciidoc/mp/integrations/neo4j.adoc +++ b/docs/src/main/asciidoc/mp/integrations/neo4j.adoc @@ -142,7 +142,7 @@ Movies can now be returned as JSON objects: include::{sourcedir}/mp/integrations/Neo4jSnippets.java[tag=snippet_3, indent=0] ---- -Now build and run with JDK17+ +Now build and run. [source,bash] ---- mvn package diff --git a/docs/src/main/asciidoc/mp/integrations/oci.adoc b/docs/src/main/asciidoc/mp/integrations/oci.adoc index 531ea63252b..dbf5e8e3927 100644 --- a/docs/src/main/asciidoc/mp/integrations/oci.adoc +++ b/docs/src/main/asciidoc/mp/integrations/oci.adoc @@ -129,4 +129,4 @@ Once you have injected an ObjectStorage client you can use it as described in: == References * link:{integration-oci-sdk-cdi-javadoc-base-url}/io/helidon/integrations/oci/sdk/cdi/OciExtension.html[OciExtension] Javadocs -* link:{helidon-github-tree-url}/examples/integrations/oci[OCI SDK Usage Examples] +* link:{helidon-github-examples-url}/integrations/oci[OCI SDK Usage Examples] diff --git a/docs/src/main/asciidoc/mp/metrics/metrics.adoc b/docs/src/main/asciidoc/mp/metrics/metrics.adoc index 009fa5d251a..636a4c7e0e6 100644 --- a/docs/src/main/asciidoc/mp/metrics/metrics.adoc +++ b/docs/src/main/asciidoc/mp/metrics/metrics.adoc @@ -123,7 +123,7 @@ include::{rootdir}/includes/metrics/metrics-config.adoc[tag=config-intro] == Examples Helidon MP includes a pre-written example application illustrating -link:{helidon-github-tree-url}/examples/metrics/filtering/mp[enabling/disabling metrics] using configuration. +link:{helidon-github-examples-url}/metrics/filtering/mp[enabling/disabling metrics] using configuration. The rest of this section contains other examples of working with metrics: diff --git a/docs/src/main/asciidoc/mp/openapi/openapi.adoc b/docs/src/main/asciidoc/mp/openapi/openapi.adoc index 7fcce8fac8a..cb201ff723a 100644 --- a/docs/src/main/asciidoc/mp/openapi/openapi.adoc +++ b/docs/src/main/asciidoc/mp/openapi/openapi.adoc @@ -94,7 +94,7 @@ Further, Helidon OpenAPI supports the MicroProfile OpenAPI settings described in == Examples -Helidon MP includes a link:{helidon-github-tree-url}/examples/microprofile/openapi[complete OpenAPI example] +Helidon MP includes a link:{helidon-github-examples-url}/microprofile/openapi[complete OpenAPI example] based on the MP quick-start sample app. The rest of this section shows, step-by-step, how one might change the original QuickStart service to adopt OpenAPI. === Helidon MP OpenAPI Example @@ -167,7 +167,7 @@ curl -X GET http://localhost:8080/openapi The output describes not only then endpoints from `GreetResource` but also one contributed by the `SimpleAPIModelReader`. -Full example is available link:{helidon-github-tree-url}/examples/microprofile/openapi[in our official repository] +Full example is available link:{helidon-github-examples-url}/microprofile/openapi[in our official repository] == Additional Information diff --git a/docs/src/main/asciidoc/mp/persistence.adoc b/docs/src/main/asciidoc/mp/persistence.adoc index f5005496497..86e9df1c7fa 100644 --- a/docs/src/main/asciidoc/mp/persistence.adoc +++ b/docs/src/main/asciidoc/mp/persistence.adoc @@ -1349,7 +1349,7 @@ relational database tables, and how to perform other related tasks. === Examples [[JPA-Examples]] -* link:{helidon-github-tree-url}/examples/integrations/cdi/pokemons[JPA +* link:{helidon-github-examples-url}/integrations/cdi/pokemons[JPA Pokemons Example] == References [[References]] diff --git a/docs/src/main/asciidoc/mp/reactivemessaging/kafka.adoc b/docs/src/main/asciidoc/mp/reactivemessaging/kafka.adoc index 6a236174e81..efbf4d99c41 100644 --- a/docs/src/main/asciidoc/mp/reactivemessaging/kafka.adoc +++ b/docs/src/main/asciidoc/mp/reactivemessaging/kafka.adoc @@ -157,4 +157,4 @@ mp.messaging: Don't forget to check out the examples with pre-configured Kafka docker image, for easy testing: -* {helidon-github-tree-url}/examples/messaging +* {helidon-github-examples-url}/messaging diff --git a/docs/src/main/asciidoc/mp/telemetry.adoc b/docs/src/main/asciidoc/mp/telemetry.adoc index 6ae961ad133..5668c6f4638 100644 --- a/docs/src/main/asciidoc/mp/telemetry.adoc +++ b/docs/src/main/asciidoc/mp/telemetry.adoc @@ -331,7 +331,7 @@ Launch the Jaeger UI at link:http://localhost:16686/[] to see the expected outpu image::telemetry/telemetry-outbound-jaeger.png[Secondary service outbound call,role="fit"] -This example is available at the link:{helidon-github-tree-url}/examples/microprofile/telemetry[Helidon official GitHub repository]. +This example is available at the link:{helidon-github-examples-url}/microprofile/telemetry[Helidon official GitHub repository]. == Reference diff --git a/docs/src/main/asciidoc/mp/websocket.adoc b/docs/src/main/asciidoc/mp/websocket.adoc index cc18f2615eb..ceb7ebcdba4 100644 --- a/docs/src/main/asciidoc/mp/websocket.adoc +++ b/docs/src/main/asciidoc/mp/websocket.adoc @@ -131,7 +131,7 @@ the root path for WebSocket endpoints will be `"/web"` instead of the default ` All endpoint methods in Helidon MP are executed in a separate thread pool, independently of Netty. Therefore, there is no need to create additional threads for blocking or long-running operations as these will not affect Netty's ability to process networking data. -For more information see the link:{helidon-github-tree-url}/examples/webserver/websocket[example]. +For more information see the link:{helidon-github-examples-url}/webserver/websocket[example]. === WebSocket Endpoints on Different Ports diff --git a/docs/src/main/asciidoc/se/cors.adoc b/docs/src/main/asciidoc/se/cors.adoc index bf57443827e..682bbe17ce1 100644 --- a/docs/src/main/asciidoc/se/cors.adoc +++ b/docs/src/main/asciidoc/se/cors.adoc @@ -135,7 +135,7 @@ include::{rootdir}/includes/cors.adoc[tag=cors-config-table] [[se-api-routing-example]] === Sample Routing Setup Using the `CrossOriginConfig` API -The link:{helidon-github-tree-url}/examples/quickstarts/helidon-quickstart-se[Helidon SE Quickstart application] +The link:{helidon-github-examples-url}/quickstarts/helidon-quickstart-se[Helidon SE Quickstart application] lets you change the greeting by sending a `PUT` request to the `/greet/greeting` resource. This example, based on the QuickStart greeting app, uses the low-level `CrossOriginConfig` API and @@ -245,7 +245,7 @@ rebuild and restart your application for any changes to take effect. == Examples -For a complete example, see {helidon-github-tree-url}/examples/cors[Helidon SE CORS Example]. +For a complete example, see {helidon-github-examples-url}/cors[Helidon SE CORS Example]. == Additional Information diff --git a/docs/src/main/asciidoc/se/dbclient.adoc b/docs/src/main/asciidoc/se/dbclient.adoc index 875a29ceca4..7525a945a80 100644 --- a/docs/src/main/asciidoc/se/dbclient.adoc +++ b/docs/src/main/asciidoc/se/dbclient.adoc @@ -279,4 +279,4 @@ Execution of a query statement will always return `Stream>`. == Additional Information Now that you understand how to build and execute statements, try it for yourself. -link:{helidon-github-tree-url}/examples/dbclient[DB Client Examples]. +link:{helidon-github-examples-url}/dbclient[DB Client Examples]. diff --git a/docs/src/main/asciidoc/se/grpc/server.adoc b/docs/src/main/asciidoc/se/grpc/server.adoc index 95be3064afd..4a17d3ad90a 100644 --- a/docs/src/main/asciidoc/se/grpc/server.adoc +++ b/docs/src/main/asciidoc/se/grpc/server.adoc @@ -182,4 +182,4 @@ include::{sourcedir}/se/grpc/ServerSnippets.java[tag=snippet_3, indent=0] The following gRPC examples for Helidon SE are available: -* link:{helidon-github-tree-url}/examples/webserver/protocols[Multiple protocols on a single WebServer] +* link:{helidon-github-examples-url}/webserver/protocols[Multiple protocols on a single WebServer] diff --git a/docs/src/main/asciidoc/se/guides/dbclient.adoc b/docs/src/main/asciidoc/se/guides/dbclient.adoc index 1cca31a8209..c472b1b4fa5 100644 --- a/docs/src/main/asciidoc/se/guides/dbclient.adoc +++ b/docs/src/main/asciidoc/se/guides/dbclient.adoc @@ -555,4 +555,4 @@ The select-book statement was invoked four times. === Summary This guide provided an introduction to the Helidon DB Client's key features. If you want to learn more, see the -Helidon DB Client samples in link:{helidon-github-tree-url}/examples/dbclient[GitHub]. +Helidon DB Client samples in link:{helidon-github-examples-url}/dbclient[GitHub]. diff --git a/docs/src/main/asciidoc/se/guides/upgrade_4x.adoc b/docs/src/main/asciidoc/se/guides/upgrade_4x.adoc index 3996d6a1122..f6a8c4b0076 100644 --- a/docs/src/main/asciidoc/se/guides/upgrade_4x.adoc +++ b/docs/src/main/asciidoc/se/guides/upgrade_4x.adoc @@ -303,4 +303,4 @@ If you use this handler in your `logging.properties` you will need to update it Please proceed to xref:../introduction.adoc[Helidon SE Introduction] to find more information and documentation about each module. Also, the -link:{helidon-github-tree-url}/examples/[Helidon examples] are a good resource for seeing how things are done in Helidon 4. +link:{helidon-github-examples-url}/[Helidon examples] are a good resource for seeing how things are done in Helidon 4. diff --git a/docs/src/main/asciidoc/se/integrations/hcv.adoc b/docs/src/main/asciidoc/se/integrations/hcv.adoc index 394c645ef64..f8151e92a4e 100644 --- a/docs/src/main/asciidoc/se/integrations/hcv.adoc +++ b/docs/src/main/asciidoc/se/integrations/hcv.adoc @@ -278,4 +278,4 @@ but it can be easily used with the examples below. == References -* link:{helidon-github-tree-url}/examples/integrations/vault[Hashicorp Vault Usage Examples] +* link:{helidon-github-examples-url}/integrations/vault[Hashicorp Vault Usage Examples] diff --git a/docs/src/main/asciidoc/se/integrations/neo4j.adoc b/docs/src/main/asciidoc/se/integrations/neo4j.adoc index 6e46674a355..1e640c6fced 100644 --- a/docs/src/main/asciidoc/se/integrations/neo4j.adoc +++ b/docs/src/main/asciidoc/se/integrations/neo4j.adoc @@ -154,11 +154,11 @@ include::{sourcedir}/se/integrations/Neo4jSnippets.java[tag=snippet_4, indent=0] <3> Use of `Neo4jHealthCheck` to add _Neo4j_ health support. <4> Register `MovieService` in _Routing_. -Now build and run with JDK17+ +Now build and run. [source,bash] ---- mvn package -java -jar target/helidon-examples-integration-neo4j-mp.jar +java -jar target/helidon-examples-integration-neo4j.jar ---- Exercise the application: @@ -177,7 +177,7 @@ curl -s -X GET http://localhost:8080/metrics curl -H 'Accept: application/json' -X GET http://localhost:8080/metrics ---- -Full example code is available in link:{helidon-github-tree-url}/examples/integrations/neo4j/neo4j-mp[Helidon GitHub Repository]. +Full example code is available in link:{helidon-github-examples-url}/integrations/neo4j[Helidon Examples Repository]. == Additional Information diff --git a/docs/src/main/asciidoc/se/integrations/oci.adoc b/docs/src/main/asciidoc/se/integrations/oci.adoc index 52741fb14f1..ceaa6037edf 100644 --- a/docs/src/main/asciidoc/se/integrations/oci.adoc +++ b/docs/src/main/asciidoc/se/integrations/oci.adoc @@ -104,5 +104,5 @@ Once you have created an ObjectStorage client you can use it as described in: == References -* link:{helidon-github-tree-url}/examples/integrations/oci[OCI SDK Usage Examples] +* link:{helidon-github-examples-url}/integrations/oci[OCI SDK Usage Examples] * link:https://docs.oracle.com/en-us/iaas/Content/home.htm[OCI Documentation] diff --git a/docs/src/main/asciidoc/se/openapi/openapi.adoc b/docs/src/main/asciidoc/se/openapi/openapi.adoc index e3333f8a732..8a4ff53a833 100644 --- a/docs/src/main/asciidoc/se/openapi/openapi.adoc +++ b/docs/src/main/asciidoc/se/openapi/openapi.adoc @@ -91,7 +91,7 @@ include::{rootdir}/config/io_helidon_openapi_OpenApiFeature.adoc[leveloffset=+1, == Examples -Helidon SE provides a link:{helidon-github-tree-url}/examples/openapi[complete OpenAPI example] +Helidon SE provides a link:{helidon-github-examples-url}/openapi[complete OpenAPI example] based on the SE QuickStart sample app. Most Helidon {flavor-uc} applications need only add the dependency as explained above; Helidon discovers and registers OpenAPI diff --git a/docs/src/main/asciidoc/se/reactive-messaging.adoc b/docs/src/main/asciidoc/se/reactive-messaging.adoc index df14c41de05..6a6ffbf2c26 100644 --- a/docs/src/main/asciidoc/se/reactive-messaging.adoc +++ b/docs/src/main/asciidoc/se/reactive-messaging.adoc @@ -301,7 +301,7 @@ include::{sourcedir}/se/ReactiveMessagingSnippets.java[tag=snippet_12, indent=0] Don't forget to check out the examples with pre-configured Kafka docker image, for easy testing: -* {helidon-github-tree-url}/examples/messaging +* {helidon-github-examples-url}/messaging ==== JMS Connector @@ -382,7 +382,7 @@ include::{sourcedir}/se/ReactiveMessagingSnippets.java[tag=snippet_16, indent=0] Don't forget to check out the examples with pre-configured ActiveMQ docker image, for easy testing: -* link:{helidon-github-tree-url}/examples/messaging[Helidon Messaging Examples] +* link:{helidon-github-examples-url}/messaging[Helidon Messaging Examples] ==== AQ Connector @@ -424,4 +424,4 @@ include::{sourcedir}/se/ReactiveMessagingSnippets.java[tag=snippet_17, indent=0] * link:{microprofile-reactive-messaging-spec-url}[MicroProfile Reactive Messaging Specification] * link:https://github.com/eclipse/microprofile-reactive-messaging[MicroProfile Reactive Messaging on GitHub] -* link:{helidon-github-tree-url}/examples/messaging[Helidon Messaging Examples] +* link:{helidon-github-examples-url}/messaging[Helidon Messaging Examples] diff --git a/docs/src/main/asciidoc/se/websocket.adoc b/docs/src/main/asciidoc/se/websocket.adoc index f21b9610811..5db6349f0e0 100644 --- a/docs/src/main/asciidoc/se/websocket.adoc +++ b/docs/src/main/asciidoc/se/websocket.adoc @@ -69,7 +69,7 @@ one at a time, over a connection. The example will show how REST and WebSocket connections can be seamlessly combined into a Helidon application. -The complete Helidon SE example is available {helidon-github-tree-url}/examples/webserver/websocket[here]. Let us start by +The complete Helidon SE example is available {helidon-github-examples-url}/webserver/websocket[here]. Let us start by looking at `MessageQueueService`: [source,java] diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 00000000000..e79be892605 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,8 @@ +

        + +

        + +# Helidon Examples + +Helidon 4 examples have moved to the [helidon-examples](https://github.com/helidon-io/helidon-examples/tree/helidon-4.x) repository. + From 45e0005087e09c3e567960e15f59a8254b539865 Mon Sep 17 00:00:00 2001 From: Joe DiPol Date: Fri, 2 Aug 2024 15:29:03 -0700 Subject: [PATCH 27/37] 4.x jakarta ee upgrades (#9089) * Upgrade Jakarta EE dependencies and some reference impls * Add seperate version for jsonb-tck --- dependencies/pom.xml | 15 ++++++++------- integrations/jta/jdbc/pom.xml | 5 +++++ .../server/src/main/java/module-info.java | 3 ++- microprofile/tests/tck/tck-jsonb/pom.xml | 4 ++-- .../tests/tck/tck-jsonb/tck-jsonb-test/pom.xml | 2 +- 5 files changed, 18 insertions(+), 11 deletions(-) diff --git a/dependencies/pom.xml b/dependencies/pom.xml index a26f8ed7fcd..d9ac96001dc 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -65,11 +65,11 @@ 4.3.1 6.3 ${version.lib.hibernate.family}.1.Final - 7.0.2.Final + 7.0.5.Final 5.0.1 1.5.18 2.15.2 - 2.1.1 + 2.1.3 2.1.1 4.0.1 5.0.1 @@ -77,14 +77,15 @@ 2.1.0 3.1.0 3.1.0 - 3.0.0 + 3.0.1 + 3.0.0 2.1.3 3.1.0 - 2.0.0 - 3.0.0 + 2.0.1 + 3.0.2 2.1.1 - 4.0.0 + 4.0.2 3.1.2 4.0.3 4.0.3 @@ -146,7 +147,7 @@ 0.2.1 0.1.8 0.25.0 - 1.1.5 + 1.1.6 42.7.2 0.16.0 1.0.4 diff --git a/integrations/jta/jdbc/pom.xml b/integrations/jta/jdbc/pom.xml index 6635e80f88f..8f924d9a54c 100644 --- a/integrations/jta/jdbc/pom.xml +++ b/integrations/jta/jdbc/pom.xml @@ -49,6 +49,11 @@ jakarta.transaction-api provided + + jakarta.enterprise + jakarta.enterprise.cdi-api + provided + diff --git a/microprofile/server/src/main/java/module-info.java b/microprofile/server/src/main/java/module-info.java index 20fe3655a7f..161737fc3db 100644 --- a/microprofile/server/src/main/java/module-info.java +++ b/microprofile/server/src/main/java/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023 Oracle and/or its affiliates. + * Copyright (c) 2018, 2024 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. @@ -45,6 +45,7 @@ requires transitive io.helidon.webserver.context; requires transitive io.helidon.webserver; requires transitive io.helidon.webserver.observe; + requires transitive jakarta.validation; requires transitive jakarta.cdi; requires transitive jakarta.json; requires transitive jakarta.ws.rs; diff --git a/microprofile/tests/tck/tck-jsonb/pom.xml b/microprofile/tests/tck/tck-jsonb/pom.xml index 5b4e2b962c1..8eb0d3c4955 100644 --- a/microprofile/tests/tck/tck-jsonb/pom.xml +++ b/microprofile/tests/tck/tck-jsonb/pom.xml @@ -32,9 +32,9 @@ Helidon Microprofile Tests TCK JSONB - jakarta-jsonb-tck-${version.lib.jakarta.jsonb-api} + jakarta-jsonb-tck-${version.lib.jakarta.jsonb-tck} https://download.eclipse.org/ee4j/jakartaee-tck/jakartaee10/promoted/eftl/${tck.filename}.zip - jakarta.json.bind-tck-${version.lib.jakarta.jsonb-api} + jakarta.json.bind-tck-${version.lib.jakarta.jsonb-tck} ${project.build.directory}/tck diff --git a/microprofile/tests/tck/tck-jsonb/tck-jsonb-test/pom.xml b/microprofile/tests/tck/tck-jsonb/tck-jsonb-test/pom.xml index 9ffb163515b..84659d42b96 100644 --- a/microprofile/tests/tck/tck-jsonb/tck-jsonb-test/pom.xml +++ b/microprofile/tests/tck/tck-jsonb/tck-jsonb-test/pom.xml @@ -39,7 +39,7 @@ jakarta.json.bind jakarta.json.bind-tck - ${version.lib.jakarta.jsonb-api} + ${version.lib.jakarta.jsonb-tck} test From 4f73c0b6afd6e0ace49b8b3ab2c9c959ab0d575f Mon Sep 17 00:00:00 2001 From: Tim Quinn Date: Sat, 3 Aug 2024 13:26:36 -0500 Subject: [PATCH 28/37] 4.x Adopt MP Telemetry 1.1 (#8984) --- dependencies/pom.xml | 10 +- docs/src/main/asciidoc/mp/telemetry.adoc | 32 ++++++- .../telemetry/etc/spotbugs/exclude.xml | 31 +++++++ microprofile/telemetry/pom.xml | 1 + .../HelidonTelemetryClientFilter.java | 24 ++++- .../HelidonTelemetryContainerFilter.java | 79 ++++++++++++++-- .../telemetry/OpenTelemetryProducer.java | 92 ++++++++++++++++++- .../telemetry/src/main/java/module-info.java | 1 + .../WithSpanUsingLegacySpanNameTest.java | 39 ++++++++ .../WithSpanWithExplicitAppTest.java | 1 + ...nWithExplicitAppUsingLegacyNamingTest.java | 40 ++++++++ microprofile/tests/tck/tck-telemetry/pom.xml | 24 ++--- .../tck/tck-telemetry/src/test/tck-suite.xml | 12 ++- .../tracing/TracingCdiExtension.java | 6 +- .../reflect-config.json | 6 ++ .../MutableOpenTelemetryBaggage.java | 13 ++- .../OpenTelemetrySpanBuilder.java | 3 +- .../io/helidon/tracing/WritableBaggage.java | 12 +++ 18 files changed, 384 insertions(+), 42 deletions(-) create mode 100644 microprofile/telemetry/etc/spotbugs/exclude.xml create mode 100644 microprofile/telemetry/src/test/java/io/helidon/microprofile/telemetry/WithSpanUsingLegacySpanNameTest.java create mode 100644 microprofile/telemetry/src/test/java/io/helidon/microprofile/telemetry/WithSpanWithExplicitAppUsingLegacyNamingTest.java diff --git a/dependencies/pom.xml b/dependencies/pom.xml index d9ac96001dc..6694d157097 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -117,7 +117,7 @@ 3.0 3.0 3.0.1 - 1.0 + 1.1 3.0 2.0 08.01.01-MS-GA @@ -139,10 +139,10 @@ 3.4.0 4.11.0 - 1.22.0-alpha - 1.22.0-alpha - 1.22.0-alpha - 1.22.0 + 1.29.0-alpha + 1.29.0 + 1.29.0 + 1.29.0 0.33.0 0.2.1 0.1.8 diff --git a/docs/src/main/asciidoc/mp/telemetry.adoc b/docs/src/main/asciidoc/mp/telemetry.adoc index 5668c6f4638..7fecd1c7349 100644 --- a/docs/src/main/asciidoc/mp/telemetry.adoc +++ b/docs/src/main/asciidoc/mp/telemetry.adoc @@ -22,6 +22,8 @@ :keywords: helidon, telemetry, microprofile, micro-profile :microprofile-bundle: true :rootdir: {docdir}/.. +:mp-telemetry-version: 1.1 +:otel-version: 1.29.0 include::{rootdir}/includes/mp.adoc[] @@ -50,7 +52,33 @@ include::{rootdir}/includes/dependencies.adoc[] link:https://opentelemetry.io/[OpenTelemetry] comprises a collection of APIs, SDKs, integration tools, and other software components intended to facilitate the generation and control of telemetry data, including traces, metrics, and logs. In an environment where distributed tracing is enabled via OpenTelemetry (which combines OpenTracing and OpenCensus), this specification establishes the necessary behaviors for MicroProfile applications to participate seamlessly. -MicroProfile Telemetry 1.0 allows for the exportation of the data it collects to Jaeger or Zipkin and to other systems using a variety of exporters. +MicroProfile Telemetry {mp-telemetry-version} allows for the exportation of the data it collects to Jaeger or Zipkin and to other systems using a variety of exporters. + +// @Deprecated(forRemoval = true) In 5.x remove the following note. +[NOTE] +.Span Names for REST Requests +==== +If possible, assign the following config setting in your application's `META-INF/microprofile-config.properties` file: +[source,properties] +---- +mp.telemetry.span.name-includes-method = true +---- +Earlier releases of Helidon 4 implemented MicroProfile Telemetry 1.0 which was based on OpenTelemetry semantic conventions 1.22.0-alpha. + +MicroProfile Telemetry {mp-telemetry-version} is based on OpenTelemetry {otel-version}, and in that release the semantic convention for the REST span name now includes the HTTPmethod name, as shown in the format below. +[source] +---- +{http-method-name} {http-request-route} +---- +(see https://opentelemetry.io/docs/specs/semconv/http/http-spans/#name) + +Although span names are often used only for display in monitoring tools, this is a backward-incompatible change. + +Therefore, Helidon {helidon-version} by default conforms to the _older_ semantic convention to preserve backward compatibility with earlier 4.x releases. Only if you set the property as shown above will Helidon {helidon-version} use the new span naming format. + +The ability to use the older format is deprecated, and you should plan for its removal in a future major release of Helidon. For that reason Helidon logs a warning message if you use the older REST span naming convention. +==== +// end of text to be removed in 5.x In a distributed tracing system, *traces* are used to capture a series of requests and are composed of multiple *spans* that represent individual operations within those requests. Each *span* includes a name, timestamps, and metadata that provide insights into the corresponding operation. @@ -335,5 +363,5 @@ This example is available at the link:{helidon-github-examples-url}/microprofile == Reference -* link:https://download.eclipse.org/microprofile/microprofile-telemetry-1.0/tracing/microprofile-telemetry-tracing-spec-1.0.pdf[MicroProfile Telemetry Specification] +* link:https://download.eclipse.org/microprofile/microprofile-telemetry-{mp-telemetry-version}/tracing/microprofile-telemetry-tracing-spec-{mp-telemetry-version}.pdf[MicroProfile Telemetry Specification] * link:https://opentelemetry.io/docs/[OpenTelemetry Documentation] diff --git a/microprofile/telemetry/etc/spotbugs/exclude.xml b/microprofile/telemetry/etc/spotbugs/exclude.xml new file mode 100644 index 00000000000..48198837112 --- /dev/null +++ b/microprofile/telemetry/etc/spotbugs/exclude.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + diff --git a/microprofile/telemetry/pom.xml b/microprofile/telemetry/pom.xml index 300b21bf105..fa3e4bc53ce 100644 --- a/microprofile/telemetry/pom.xml +++ b/microprofile/telemetry/pom.xml @@ -35,6 +35,7 @@ 100 + etc/spotbugs/exclude.xml diff --git a/microprofile/telemetry/src/main/java/io/helidon/microprofile/telemetry/HelidonTelemetryClientFilter.java b/microprofile/telemetry/src/main/java/io/helidon/microprofile/telemetry/HelidonTelemetryClientFilter.java index e05b8a25f84..f506661cccd 100644 --- a/microprofile/telemetry/src/main/java/io/helidon/microprofile/telemetry/HelidonTelemetryClientFilter.java +++ b/microprofile/telemetry/src/main/java/io/helidon/microprofile/telemetry/HelidonTelemetryClientFilter.java @@ -17,24 +17,29 @@ import java.util.List; import java.util.Optional; +import java.util.Set; import io.helidon.tracing.HeaderConsumer; import io.helidon.tracing.HeaderProvider; import io.helidon.tracing.Scope; import io.helidon.tracing.Span; +import io.opentelemetry.api.baggage.Baggage; +import io.opentelemetry.context.Context; import jakarta.inject.Inject; import jakarta.ws.rs.client.ClientRequestContext; import jakarta.ws.rs.client.ClientRequestFilter; import jakarta.ws.rs.client.ClientResponseContext; import jakarta.ws.rs.client.ClientResponseFilter; import jakarta.ws.rs.core.MultivaluedMap; +import jakarta.ws.rs.core.Response; import jakarta.ws.rs.ext.Provider; import static io.helidon.microprofile.telemetry.HelidonTelemetryConstants.HTTP_METHOD; import static io.helidon.microprofile.telemetry.HelidonTelemetryConstants.HTTP_SCHEME; import static io.helidon.microprofile.telemetry.HelidonTelemetryConstants.HTTP_STATUS_CODE; - +import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.NET_PEER_NAME; +import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.NET_PEER_PORT; /** * Filter to process Client request and Client response. Starts a new {@link io.opentelemetry.api.trace.Span} on request and @@ -46,6 +51,9 @@ class HelidonTelemetryClientFilter implements ClientRequestFilter, ClientRespons private static final String HTTP_URL = "http.url"; private static final String SPAN_SCOPE = Scope.class.getName(); private static final String SPAN = Span.class.getName(); + private static final Set ERROR_STATUS_FAMILIES = Set.of( + Response.Status.Family.CLIENT_ERROR, + Response.Status.Family.SERVER_ERROR); private final io.helidon.tracing.Tracer helidonTracer; @@ -69,11 +77,18 @@ public void filter(ClientRequestContext clientRequestContext) { .tag(HTTP_METHOD, clientRequestContext.getMethod()) .tag(HTTP_SCHEME, clientRequestContext.getUri().getScheme()) .tag(HTTP_URL, clientRequestContext.getUri().toString()) + .tag(NET_PEER_NAME.getKey(), clientRequestContext.getUri().getHost()) + .tag(NET_PEER_PORT.getKey(), clientRequestContext.getUri().getPort()) .update(builder -> Span.current() .map(Span::context) .ifPresent(builder::parent)) .start(); + Baggage.fromContext(Context.current()) + .forEach((key, baggageEntry) -> + helidonSpan.baggage().set(key, + baggageEntry.getValue(), + baggageEntry.getMetadata().getValue())); Scope helidonScope = helidonSpan.activate(); clientRequestContext.setProperty(SPAN_SCOPE, helidonScope); @@ -100,6 +115,13 @@ public void filter(ClientRequestContext clientRequestContext, ClientResponseCont scope.close(); span.tag(HTTP_STATUS_CODE, clientResponseContext.getStatus()); + + // OpenTelemetry semantic conventions dictate what the span status should be. + // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status + if (ERROR_STATUS_FAMILIES.contains(clientResponseContext.getStatusInfo().getFamily())) { + span.status(Span.Status.ERROR); + } + span.end(); clientRequestContext.removeProperty(SPAN); diff --git a/microprofile/telemetry/src/main/java/io/helidon/microprofile/telemetry/HelidonTelemetryContainerFilter.java b/microprofile/telemetry/src/main/java/io/helidon/microprofile/telemetry/HelidonTelemetryContainerFilter.java index 9b905c4949d..f361d54b84e 100644 --- a/microprofile/telemetry/src/main/java/io/helidon/microprofile/telemetry/HelidonTelemetryContainerFilter.java +++ b/microprofile/telemetry/src/main/java/io/helidon/microprofile/telemetry/HelidonTelemetryContainerFilter.java @@ -18,15 +18,20 @@ import java.util.Deque; import java.util.LinkedList; import java.util.List; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicBoolean; import io.helidon.common.context.Contexts; import io.helidon.config.mp.MpConfig; import io.helidon.tracing.Scope; import io.helidon.tracing.Span; +import io.helidon.tracing.SpanContext; import io.helidon.tracing.providers.opentelemetry.HelidonOpenTelemetry; import io.opentelemetry.api.baggage.Baggage; +import io.opentelemetry.api.baggage.BaggageEntryMetadata; import io.opentelemetry.context.Context; +import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; import jakarta.inject.Inject; import jakarta.ws.rs.ApplicationPath; import jakarta.ws.rs.container.ContainerRequestContext; @@ -35,6 +40,7 @@ import jakarta.ws.rs.container.ContainerResponseFilter; import jakarta.ws.rs.container.ResourceInfo; import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.Response; import jakarta.ws.rs.ext.Provider; import org.glassfish.jersey.server.ExtendedUriInfo; import org.glassfish.jersey.server.model.Resource; @@ -53,14 +59,27 @@ class HelidonTelemetryContainerFilter implements ContainerRequestFilter, Contain private static final String SPAN = Span.class.getName(); private static final String SPAN_SCOPE = Scope.class.getName(); private static final String HTTP_TARGET = "http.target"; + private static final String HTTP_ROUTE = "http.route"; private static final String SPAN_NAME_FULL_URL = "telemetry.span.full.url"; + @Deprecated(forRemoval = true, since = "4.1") + static final String SPAN_NAME_INCLUDES_METHOD = "telemetry.span.name-includes-method"; + private static boolean spanNameFullUrl = false; + private static AtomicBoolean spanNameWarningLogged = new AtomicBoolean(); private final io.helidon.tracing.Tracer helidonTracer; private final boolean isAgentPresent; + /* + MP Telemetry 1.1 adopts OpenTelemetry 1.29 semantic conventions which require the route to be in the REST span name. + Because Helidon adopts MP Telemetry 1.1 in a dot release (4.1), this would be a backward-incompatible change. This setting, + controllable via config, defaults to the older behavior that is backward-compatible with Helidon 4.0.x but allows users to + select the newer, spec-compliant behavior that is backward-incompatible with Helidon 4.0.x. The default is to use the + old behavior. + */ + private final boolean restSpanNameIncludesMethod; @jakarta.ws.rs.core.Context private ResourceInfo resourceInfo; @@ -71,7 +90,22 @@ class HelidonTelemetryContainerFilter implements ContainerRequestFilter, Contain this.helidonTracer = helidonTracer; isAgentPresent = HelidonOpenTelemetry.AgentDetector.isAgentPresent(MpConfig.toHelidonConfig(mpConfig)); + // @Deprecated(forRemoval = true) In 5.x remove the following. mpConfig.getOptionalValue(SPAN_NAME_FULL_URL, Boolean.class).ifPresent(e -> spanNameFullUrl = e); + Optional includeMethodConfig = mpConfig.getOptionalValue(SPAN_NAME_INCLUDES_METHOD, Boolean.class); + restSpanNameIncludesMethod = includeMethodConfig.orElse(false); + if (!restSpanNameIncludesMethod && !spanNameWarningLogged.get()) { + spanNameWarningLogged.set(true); + LOGGER.log(System.Logger.Level.WARNING, + String.format(""" + Current OpenTelemetry semantic conventions include the HTTP method as part of REST span + names. Your configuration does not set mp.%s to true, so your service uses the legacy span name + format which excludes the HTTP method. This feature is deprecated and marked for removal in a + future major release of Helidon. Consider adding a setting of mp.%1$s to 'true' in your + configuration to migrate to the current conventions.""", + SPAN_NAME_INCLUDES_METHOD)); + } + // end of code to remove in 5.x. } @Override @@ -86,13 +120,18 @@ public void filter(ContainerRequestContext requestContext) { } //Start new span for container request. - Span helidonSpan = helidonTracer.spanBuilder(spanName(requestContext)) + String route = route(requestContext); + Optional extractedSpanContext = + helidonTracer.extract(new RequestContextHeaderProvider(requestContext.getHeaders())); + Span helidonSpan = helidonTracer.spanBuilder(spanName(requestContext, route)) .kind(Span.Kind.SERVER) .tag(HTTP_METHOD, requestContext.getMethod()) .tag(HTTP_SCHEME, requestContext.getUriInfo().getRequestUri().getScheme()) .tag(HTTP_TARGET, resolveTarget(requestContext)) - .update(builder -> helidonTracer.extract(new RequestContextHeaderProvider(requestContext.getHeaders())) - .ifPresent(builder::parent)) + .tag(HTTP_ROUTE, route) + .tag(SemanticAttributes.NET_HOST_NAME.getKey(), requestContext.getUriInfo().getBaseUri().getHost()) + .tag(SemanticAttributes.NET_HOST_PORT.getKey(), requestContext.getUriInfo().getBaseUri().getPort()) + .update(builder -> extractedSpanContext.ifPresent(builder::parent)) .start(); Scope helidonScope = helidonSpan.activate(); @@ -125,6 +164,12 @@ public void filter(final ContainerRequestContext request, final ContainerRespons scope.close(); span.tag(HTTP_STATUS_CODE, response.getStatus()); + + // OpenTelemetry semantic conventions dictate what the span status should be. + // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status + if (response.getStatusInfo().getFamily().compareTo(Response.Status.Family.SERVER_ERROR) == 0) { + span.status(Span.Status.ERROR); + } span.end(); @@ -134,18 +179,29 @@ public void filter(final ContainerRequestContext request, final ContainerRespons } } - private String spanName(ContainerRequestContext requestContext) { + private String spanName(ContainerRequestContext requestContext, String route) { + // @Deprecated(forRemoval = true) In 5.x remove the option of excluding the HTTP method from the REST span name. + // Starting in 5.x this method should be: + // return requestContext.getMethod() + " " + ( + // spanNameFullUrl + // ? requestContext.getUriInfo().getAbsolutePath().toString() + // : route); + // // According to recent OpenTelemetry semantic conventions for spans, the span name for a REST endpoint should be // // http-method-name low-cardinality-path // // where a low-cardinality path would be, for example /greet/{name} rather than /greet/Joe, /greet/Dmitry, etc. - // But the version of semantic conventions in force when the MP Telemetry spec was published did not include the - // http-method-name. So our code omits that for now to pass the MP Telemetry TCK. + // But the semantic conventions in place with MicroProfile Telemetry 1.0 did not include the method name in the span name. + // Users can control the span name either by requesting the full URL be used or by requesting that the method NOT + // be included. + return (restSpanNameIncludesMethod ? requestContext.getMethod() + " " : "") + ( + spanNameFullUrl + ? requestContext.getUriInfo().getAbsolutePath().toString() + : route); + } - if (spanNameFullUrl) { - return requestContext.getUriInfo().getAbsolutePath().toString(); - } + private String route(ContainerRequestContext requestContext) { ExtendedUriInfo extendedUriInfo = (ExtendedUriInfo) requestContext.getUriInfo(); // Derive the original path (including path parameters) of the matched resource from the bottom up. @@ -196,8 +252,11 @@ private void handleBaggage(ContainerRequestContext containerRequestContext, Cont for (String b : baggageProperties) { String[] split = b.split("="); if (split.length == 2) { + String[] valueAndMetadata = split[1].split(";"); + String value = valueAndMetadata.length > 0 ? valueAndMetadata[0] : ""; + String metadata = valueAndMetadata.length > 1 ? valueAndMetadata[1] : ""; Baggage.builder() - .put(split[0], split[1]) + .put(split[0], value, BaggageEntryMetadata.create(metadata)) .build() .storeInContext(context) .makeCurrent(); diff --git a/microprofile/telemetry/src/main/java/io/helidon/microprofile/telemetry/OpenTelemetryProducer.java b/microprofile/telemetry/src/main/java/io/helidon/microprofile/telemetry/OpenTelemetryProducer.java index b51a8e4228a..1c5a086e5ab 100644 --- a/microprofile/telemetry/src/main/java/io/helidon/microprofile/telemetry/OpenTelemetryProducer.java +++ b/microprofile/telemetry/src/main/java/io/helidon/microprofile/telemetry/OpenTelemetryProducer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2024 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. @@ -18,6 +18,8 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.function.BiConsumer; import io.helidon.config.Config; import io.helidon.tracing.providers.opentelemetry.HelidonOpenTelemetry; @@ -26,7 +28,13 @@ import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.baggage.Baggage; +import io.opentelemetry.api.baggage.BaggageBuilder; +import io.opentelemetry.api.baggage.BaggageEntry; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.StatusCode; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; @@ -93,8 +101,7 @@ private void init() { .addPropertiesCustomizer(x -> telemetryProperties) .addResourceCustomizer(this::customizeResource) .setServiceClassLoader(Thread.currentThread().getContextClassLoader()) - .setResultAsGlobal(false) - .registerShutdownHook(false) + .disableShutdownHook() .build() .getOpenTelemetrySdk(); @@ -159,7 +166,57 @@ io.helidon.tracing.Tracer helidonTracer() { */ @Produces Span span() { - return Span.current(); + return new Span() { + @Override + public Span setAttribute(AttributeKey key, T value) { + return Span.current().setAttribute(key, value); + } + + @Override + public Span addEvent(String name, Attributes attributes) { + return Span.current().addEvent(name, attributes); + } + + @Override + public Span addEvent(String name, Attributes attributes, long timestamp, TimeUnit unit) { + return Span.current().addEvent(name, attributes, timestamp, unit); + } + + @Override + public Span setStatus(StatusCode statusCode, String description) { + return Span.current().setStatus(statusCode, description); + } + + @Override + public Span recordException(Throwable exception, Attributes additionalAttributes) { + return Span.current().recordException(exception, additionalAttributes); + } + + @Override + public Span updateName(String name) { + return Span.current().updateName(name); + } + + @Override + public void end() { + Span.current().end(); + } + + @Override + public void end(long timestamp, TimeUnit unit) { + Span.current().end(timestamp, unit); + } + + @Override + public SpanContext getSpanContext() { + return Span.current().getSpanContext(); + } + + @Override + public boolean isRecording() { + return Span.current().isRecording(); + } + }; } /** @@ -170,7 +227,32 @@ Span span() { @Produces @ApplicationScoped Baggage baggage() { - return Baggage.current(); + return new Baggage() { + @Override + public int size() { + return Baggage.current().size(); + } + + @Override + public void forEach(BiConsumer consumer) { + Baggage.current().forEach(consumer); + } + + @Override + public Map asMap() { + return Baggage.current().asMap(); + } + + @Override + public String getEntryValue(String entryKey) { + return Baggage.current().getEntryValue(entryKey); + } + + @Override + public BaggageBuilder toBuilder() { + return Baggage.current().toBuilder(); + } + }; } diff --git a/microprofile/telemetry/src/main/java/module-info.java b/microprofile/telemetry/src/main/java/module-info.java index 766b3b7d6d5..f56c961d88a 100644 --- a/microprofile/telemetry/src/main/java/module-info.java +++ b/microprofile/telemetry/src/main/java/module-info.java @@ -48,6 +48,7 @@ requires jakarta.inject; requires microprofile.config.api; requires opentelemetry.instrumentation.annotations; + requires io.opentelemetry.semconv; requires static io.helidon.common.features.api; diff --git a/microprofile/telemetry/src/test/java/io/helidon/microprofile/telemetry/WithSpanUsingLegacySpanNameTest.java b/microprofile/telemetry/src/test/java/io/helidon/microprofile/telemetry/WithSpanUsingLegacySpanNameTest.java new file mode 100644 index 00000000000..3257cdb1608 --- /dev/null +++ b/microprofile/telemetry/src/test/java/io/helidon/microprofile/telemetry/WithSpanUsingLegacySpanNameTest.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024 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.microprofile.telemetry; + +import java.util.stream.Stream; + +import io.helidon.microprofile.testing.junit5.AddConfig; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@AddConfig(key = HelidonTelemetryContainerFilter.SPAN_NAME_INCLUDES_METHOD, + value = "false") +class WithSpanUsingLegacySpanNameTest extends WithSpanTestBase { + + @ParameterizedTest() + @MethodSource() + void testDefaultAppSpanNameFromPath(SpanPathTestInfo spanPathTestInfo) { + testSpanNameFromPath(spanPathTestInfo); + } + + static Stream testDefaultAppSpanNameFromPath() { + return Stream.of(new SpanPathTestInfo("traced", "/traced"), + new SpanPathTestInfo("traced/sub/data", "/traced/sub/{name}")); + } +} diff --git a/microprofile/telemetry/src/test/java/io/helidon/microprofile/telemetry/WithSpanWithExplicitAppTest.java b/microprofile/telemetry/src/test/java/io/helidon/microprofile/telemetry/WithSpanWithExplicitAppTest.java index 1c978a0115c..24a51ba581b 100644 --- a/microprofile/telemetry/src/test/java/io/helidon/microprofile/telemetry/WithSpanWithExplicitAppTest.java +++ b/microprofile/telemetry/src/test/java/io/helidon/microprofile/telemetry/WithSpanWithExplicitAppTest.java @@ -18,6 +18,7 @@ import java.util.stream.Stream; import io.helidon.microprofile.testing.junit5.AddBean; +import io.helidon.microprofile.testing.junit5.AddConfig; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; diff --git a/microprofile/telemetry/src/test/java/io/helidon/microprofile/telemetry/WithSpanWithExplicitAppUsingLegacyNamingTest.java b/microprofile/telemetry/src/test/java/io/helidon/microprofile/telemetry/WithSpanWithExplicitAppUsingLegacyNamingTest.java new file mode 100644 index 00000000000..e7214864640 --- /dev/null +++ b/microprofile/telemetry/src/test/java/io/helidon/microprofile/telemetry/WithSpanWithExplicitAppUsingLegacyNamingTest.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 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.microprofile.telemetry; + +import java.util.stream.Stream; + +import io.helidon.microprofile.testing.junit5.AddBean; +import io.helidon.microprofile.testing.junit5.AddConfig; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@AddBean(App.class) +@AddBean(AppTracedResource.class) +class WithSpanWithExplicitAppUsingLegacyNamingTest extends WithSpanTestBase { + + @ParameterizedTest() + @MethodSource() + void testExplicitAppSpanNameFromPath(SpanPathTestInfo spanPathTestInfo) { + testSpanNameFromPath(spanPathTestInfo); + } + + static Stream testExplicitAppSpanNameFromPath() { + return Stream.of(new SpanPathTestInfo("topapp/apptraced", "/topapp/apptraced"), + new SpanPathTestInfo("topapp/apptraced/sub/data", "/topapp/apptraced/sub/{name}")); + } +} diff --git a/microprofile/tests/tck/tck-telemetry/pom.xml b/microprofile/tests/tck/tck-telemetry/pom.xml index 7cc9a288a60..d608124431b 100644 --- a/microprofile/tests/tck/tck-telemetry/pom.xml +++ b/microprofile/tests/tck/tck-telemetry/pom.xml @@ -36,11 +36,6 @@ ${project.version} test - - org.jboss.arquillian.testng - arquillian-testng-container - test - io.opentelemetry opentelemetry-exporter-otlp @@ -71,16 +66,11 @@ helidon-microprofile-server test - + org.testng testng test - - io.helidon.logging - helidon-logging-jul - test - @@ -93,6 +83,18 @@ --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED + + + + true + src/test/tck-suite.xml diff --git a/microprofile/tests/tck/tck-telemetry/src/test/tck-suite.xml b/microprofile/tests/tck/tck-telemetry/src/test/tck-suite.xml index ce7ab140d1c..0e41430919f 100644 --- a/microprofile/tests/tck/tck-telemetry/src/test/tck-suite.xml +++ b/microprofile/tests/tck/tck-telemetry/src/test/tck-suite.xml @@ -1,7 +1,7 @@ + + + diff --git a/microprofile/tracing/src/main/java/io/helidon/microprofile/tracing/TracingCdiExtension.java b/microprofile/tracing/src/main/java/io/helidon/microprofile/tracing/TracingCdiExtension.java index 0a7380d64b5..98628ccfa62 100644 --- a/microprofile/tracing/src/main/java/io/helidon/microprofile/tracing/TracingCdiExtension.java +++ b/microprofile/tracing/src/main/java/io/helidon/microprofile/tracing/TracingCdiExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023 Oracle and/or its affiliates. + * Copyright (c) 2019, 2024 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. @@ -29,6 +29,7 @@ import io.helidon.tracing.config.TracingConfig; import io.helidon.webserver.observe.tracing.TracingObserver; +import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.opentracingshim.OpenTracingShim; import io.opentracing.Tracer; import io.opentracing.util.GlobalTracer; @@ -91,8 +92,7 @@ private void setupTracer(@Observes @Priority(PLATFORM_BEFORE) @RuntimeStart Conf registeredTracer = tracer.unwrap(Tracer.class); } catch (Exception e) { try { - io.opentelemetry.api.trace.Tracer otelTracer = tracer.unwrap(io.opentelemetry.api.trace.Tracer.class); - registeredTracer = OpenTracingShim.createTracerShim(otelTracer); + registeredTracer = OpenTracingShim.createTracerShim(GlobalOpenTelemetry.get()); } catch (Exception ex) { throw new DeploymentException("MicroProfile tracing requires an OpenTracing or OpenTelemetry based tracer", ex); } diff --git a/tracing/providers/jaeger/src/main/resources/META-INF/native-image/io.helidon.tracing.providers/helidon-tracing-providers-jaeger/reflect-config.json b/tracing/providers/jaeger/src/main/resources/META-INF/native-image/io.helidon.tracing.providers/helidon-tracing-providers-jaeger/reflect-config.json index c37848ea954..8397beabee7 100644 --- a/tracing/providers/jaeger/src/main/resources/META-INF/native-image/io.helidon.tracing.providers/helidon-tracing-providers-jaeger/reflect-config.json +++ b/tracing/providers/jaeger/src/main/resources/META-INF/native-image/io.helidon.tracing.providers/helidon-tracing-providers-jaeger/reflect-config.json @@ -7,5 +7,11 @@ "parameterTypes": [] } ] + }, + { + "condition": { + "typeReachable": "io.opentelemetry.sdk.OpenTelemetrySdk" + }, + "name": "io.opentelemetry.sdk.common.export.RetryPolicy" } ] diff --git a/tracing/providers/opentelemetry/src/main/java/io/helidon/tracing/providers/opentelemetry/MutableOpenTelemetryBaggage.java b/tracing/providers/opentelemetry/src/main/java/io/helidon/tracing/providers/opentelemetry/MutableOpenTelemetryBaggage.java index e73286773d7..fe51c990ec2 100644 --- a/tracing/providers/opentelemetry/src/main/java/io/helidon/tracing/providers/opentelemetry/MutableOpenTelemetryBaggage.java +++ b/tracing/providers/opentelemetry/src/main/java/io/helidon/tracing/providers/opentelemetry/MutableOpenTelemetryBaggage.java @@ -89,9 +89,13 @@ public BaggageBuilder toBuilder() { } void baggage(String key, String value) { + baggage(key, value, ""); + } + + void baggage(String key, String value, String metadata) { Objects.requireNonNull(key, "baggage key cannot be null"); Objects.requireNonNull(value, "baggage value cannot be null"); - values.put(key, new HBaggageEntry(value, new HBaggageEntryMetadata(""))); + values.put(key, new HBaggageEntry(value, new HBaggageEntryMetadata(metadata))); } @Override @@ -115,7 +119,12 @@ public boolean containsKey(String key) { @Override public WritableBaggage set(String key, String value) { - baggage(key, value); + return set(key, value, ""); + } + + @Override + public WritableBaggage set(String key, String value, String metadata) { + baggage(key, value, metadata); return this; } diff --git a/tracing/providers/opentelemetry/src/main/java/io/helidon/tracing/providers/opentelemetry/OpenTelemetrySpanBuilder.java b/tracing/providers/opentelemetry/src/main/java/io/helidon/tracing/providers/opentelemetry/OpenTelemetrySpanBuilder.java index 4f07c22e0c9..d75f8d6e3f9 100644 --- a/tracing/providers/opentelemetry/src/main/java/io/helidon/tracing/providers/opentelemetry/OpenTelemetrySpanBuilder.java +++ b/tracing/providers/opentelemetry/src/main/java/io/helidon/tracing/providers/opentelemetry/OpenTelemetrySpanBuilder.java @@ -99,7 +99,8 @@ public Span start(Instant instant) { io.opentelemetry.api.trace.Span span = spanBuilder.startSpan(); OpenTelemetrySpan result = new OpenTelemetrySpan(span, spanListeners); if (parentBaggage != null) { - parentBaggage.forEach((key, baggageEntry) -> result.baggage().set(key, baggageEntry.getValue())); + parentBaggage.forEach((key, baggageEntry) -> result.baggage() + .set(key, baggageEntry.getValue(), baggageEntry.getMetadata().getValue())); } HelidonOpenTelemetry.invokeListeners(spanListeners, LOGGER, listener -> listener.started(result.limited())); diff --git a/tracing/tracing/src/main/java/io/helidon/tracing/WritableBaggage.java b/tracing/tracing/src/main/java/io/helidon/tracing/WritableBaggage.java index 313dbe9fae1..961ce6ab625 100644 --- a/tracing/tracing/src/main/java/io/helidon/tracing/WritableBaggage.java +++ b/tracing/tracing/src/main/java/io/helidon/tracing/WritableBaggage.java @@ -28,4 +28,16 @@ public interface WritableBaggage extends Baggage { * @return the baggage instance (for chained invocation) */ WritableBaggage set(String key, String value); + + /** + * Adds a new or overrides an existing setting for the specified key using the provided value and baggage metadata. + * + * @param key name of the entry to add or update + * @param value value to assign to the entry + * @param metadata metadata to assign to the entry + * @return the baggage instance (for chained invocation) + */ + default WritableBaggage set(String key, String value, String metadata) { + return set(key, value); + } } From b9f19f49aa85df673d2663c96f8c066becf059fe Mon Sep 17 00:00:00 2001 From: Joe DiPol Date: Mon, 5 Aug 2024 08:03:27 -0700 Subject: [PATCH 29/37] Update microprofile spec versions in docs (#9095) --- docs/src/main/asciidoc/includes/attributes.adoc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/src/main/asciidoc/includes/attributes.adoc b/docs/src/main/asciidoc/includes/attributes.adoc index cc1d001d9e9..520f68b7226 100644 --- a/docs/src/main/asciidoc/includes/attributes.adoc +++ b/docs/src/main/asciidoc/includes/attributes.adoc @@ -41,7 +41,7 @@ endif::[] // versions :version-plugin-helidon: 3.0.5 -:version-lib-microprofile-api: 6.0 +:version-lib-microprofile-api: 6.1 // microprofile specifications :version-lib-microprofile-lra-api: 2.0 @@ -50,13 +50,13 @@ endif::[] :version-lib-microprofile-graphql: 2.0 :version-lib-microprofile-health: 4.0 :version-lib-microprofile-jwt: 2.1 -:version-lib-microprofile-metrics-api: 5.0.1 -:version-lib-microprofile-openapi-api: 3.1 +:version-lib-microprofile-metrics-api: 5.1.1 +:version-lib-microprofile-openapi-api: 3.1.1 :version-lib-microprofile-reactive-messaging-api: 3.0 :version-lib-microprofile-rs-operators-api: 3.0 :version-lib-microprofile-rest-client: 3.0 -:version-lib-microprofile-telemetry-tck: 1.0 -:version-lib-microprofile-telemetry: 1.0 +:version-lib-microprofile-telemetry-tck: 1.1 +:version-lib-microprofile-telemetry: 1.1 :version-lib-microprofile-tracing: 3.0 // jakarta specifications From 8bd5d41caeee0f1de2c69c059ae5c8d42e519eca Mon Sep 17 00:00:00 2001 From: Tim Quinn Date: Mon, 5 Aug 2024 16:38:35 -0500 Subject: [PATCH 30/37] Add deprecation logging and mention in Micrometer integration doc pages (#9100) Signed-off-by: Tim Quinn --- .../main/asciidoc/includes/metrics/micrometer-shared.adoc | 8 ++++++++ .../micrometer/cdi/MicrometerCdiExtension.java | 7 ++++++- .../integrations/micrometer/MicrometerFeature.java | 3 +++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/docs/src/main/asciidoc/includes/metrics/micrometer-shared.adoc b/docs/src/main/asciidoc/includes/metrics/micrometer-shared.adoc index 14c8a293186..630f50b2909 100644 --- a/docs/src/main/asciidoc/includes/metrics/micrometer-shared.adoc +++ b/docs/src/main/asciidoc/includes/metrics/micrometer-shared.adoc @@ -29,6 +29,14 @@ endif::[] :keywords: helidon, java, micrometer, integration, se, mp == Overview + +[NOTE] +==== +Micrometer integration is deprecated beginning in Helidon 4.1 and is planned for removal in a future major release. Please use +ifdef::se-flavor[the link:{rootdir}/se/metrics/metrics.adoc[Helidon neutral metrics API].] +ifdef::mp-flavor[the link:{rootdir}/mp/metrics/metrics.adoc[Helidon MicroProfile Metrics API implementation and annotations].] +==== + Helidon {h1-prefix} simplifies how you can use Micrometer for application-specific metrics: * The endpoint `/micrometer`: A configurable endpoint that exposes metrics according to which Micrometer meter registry diff --git a/integrations/micrometer/cdi/src/main/java/io/helidon/integrations/micrometer/cdi/MicrometerCdiExtension.java b/integrations/micrometer/cdi/src/main/java/io/helidon/integrations/micrometer/cdi/MicrometerCdiExtension.java index d744be80eba..06ac0719374 100644 --- a/integrations/micrometer/cdi/src/main/java/io/helidon/integrations/micrometer/cdi/MicrometerCdiExtension.java +++ b/integrations/micrometer/cdi/src/main/java/io/helidon/integrations/micrometer/cdi/MicrometerCdiExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. + * Copyright (c) 2021, 2024 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. @@ -57,7 +57,10 @@ /** * CDI extension for handling Micrometer artifacts. + * + * @deprecated To be removed in a future release. No replacement. */ +@Deprecated(forRemoval = true, since = "4.1") public class MicrometerCdiExtension extends HelidonRestCdiExtension { private static final System.Logger LOGGER = System.getLogger(MicrometerCdiExtension.class.getName()); @@ -126,6 +129,8 @@ public void registerService(@Observes @Priority(LIBRARY_BEFORE + 10) @Initialize annotation.annotationType(), MeterWorkItem.create(newMeter, isOnlyOnException)); }); + + LOGGER.log(Level.WARNING, "Micrometer integration is deprecated and will be removed in a future major release."); } MeterRegistry meterRegistry() { if (feature == null) { diff --git a/integrations/micrometer/micrometer/src/main/java/io/helidon/integrations/micrometer/MicrometerFeature.java b/integrations/micrometer/micrometer/src/main/java/io/helidon/integrations/micrometer/MicrometerFeature.java index 2a1387f7c39..8fa0199e130 100644 --- a/integrations/micrometer/micrometer/src/main/java/io/helidon/integrations/micrometer/MicrometerFeature.java +++ b/integrations/micrometer/micrometer/src/main/java/io/helidon/integrations/micrometer/MicrometerFeature.java @@ -49,6 +49,7 @@ public class MicrometerFeature extends HelidonFeatureSupport { static final String DEFAULT_CONTEXT = "/micrometer"; private static final String SERVICE_NAME = "Micrometer"; + private static final System.Logger LOGGER = System.getLogger(MicrometerFeature.class.getName()); private final MeterRegistryFactory meterRegistryFactory; @@ -105,6 +106,8 @@ protected void postSetup(HttpRouting.Builder defaultRouting, HttpRouting.Builder @Override public void beforeStart() { Contexts.globalContext().register(registry()); + LOGGER.log(System.Logger.Level.WARNING, + "Micrometer integration is deprecated and will be removed in a future major release."); } private void getOrOptions(ServerRequest serverRequest, ServerResponse serverResponse) throws Exception { From ec01d778ab8987084ccda570ed11c20a5d96f028 Mon Sep 17 00:00:00 2001 From: Romain Grecourt Date: Mon, 5 Aug 2024 16:25:53 -0700 Subject: [PATCH 31/37] Fix DbClientService for Mongo DbClient (#9102) Fixes #9101 --- .../dbclient/mongodb/MongoDbStatementDml.java | 3 +- .../mongodb/MongoDbStatementQuery.java | 17 ++-- .../dbclient/mongodb/MongoDbClientTest.java | 83 +++++++++++++++++-- 3 files changed, 90 insertions(+), 13 deletions(-) diff --git a/dbclient/mongodb/src/main/java/io/helidon/dbclient/mongodb/MongoDbStatementDml.java b/dbclient/mongodb/src/main/java/io/helidon/dbclient/mongodb/MongoDbStatementDml.java index 0b1f52d49f5..f22d3d7adb1 100644 --- a/dbclient/mongodb/src/main/java/io/helidon/dbclient/mongodb/MongoDbStatementDml.java +++ b/dbclient/mongodb/src/main/java/io/helidon/dbclient/mongodb/MongoDbStatementDml.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023 Oracle and/or its affiliates. + * Copyright (c) 2019, 2024 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. @@ -63,6 +63,7 @@ public long execute() { "Statement operation not yet supported: %s", type.name())); }; + future.complete(result); LOGGER.log(System.Logger.Level.DEBUG, () -> String.format( "%s DML %s execution succeeded", type.name(), diff --git a/dbclient/mongodb/src/main/java/io/helidon/dbclient/mongodb/MongoDbStatementQuery.java b/dbclient/mongodb/src/main/java/io/helidon/dbclient/mongodb/MongoDbStatementQuery.java index fe9ea5218a9..f142e39fb7d 100644 --- a/dbclient/mongodb/src/main/java/io/helidon/dbclient/mongodb/MongoDbStatementQuery.java +++ b/dbclient/mongodb/src/main/java/io/helidon/dbclient/mongodb/MongoDbStatementQuery.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023 Oracle and/or its affiliates. + * Copyright (c) 2019, 2024 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. @@ -17,6 +17,7 @@ import java.lang.System.Logger.Level; import java.util.Spliterator; +import java.util.concurrent.CompletableFuture; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -28,6 +29,7 @@ import com.mongodb.client.FindIterable; import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoCursor; import com.mongodb.client.MongoDatabase; import org.bson.Document; @@ -62,8 +64,8 @@ public Stream execute() { try { MongoStatement stmt = queryOrCommand(preparedStmt); return switch (stmt.getOperation()) { - case QUERY -> executeQuery(stmt); - case COMMAND -> executeCommand(stmt); + case QUERY -> executeQuery(stmt, future); + case COMMAND -> executeCommand(stmt, future); default -> throw new UnsupportedOperationException(String.format( "Operation %s is not supported by query", stmt.getOperation().toString())); }; @@ -87,14 +89,15 @@ private MongoStatement queryOrCommand(String statement) { } } - private Stream executeCommand(MongoStatement stmt) { + private Stream executeCommand(MongoStatement stmt, CompletableFuture future) { Document command = stmt.getQuery(); LOGGER.log(Level.DEBUG, () -> String.format("Command: %s", command.toString())); Document doc = db().runCommand(command); + future.complete(1L); return Stream.of(new MongoDbRow(doc, context())); } - private Stream executeQuery(MongoStatement stmt) { + private Stream executeQuery(MongoStatement stmt, CompletableFuture future) { MongoCollection mc = db().getCollection(stmt.getCollection()); Document query = stmt.getQuery(); Document projection = stmt.getProjection(); @@ -109,7 +112,9 @@ private Stream executeQuery(MongoStatement stmt) { finder = finder.projection(projection); } - Spliterator spliterator = spliteratorUnknownSize(finder.iterator(), Spliterator.ORDERED); + MongoCursor it = finder.iterator(); + future.complete(it.hasNext() ? 1L : 0L); + Spliterator spliterator = spliteratorUnknownSize(it, Spliterator.ORDERED); Stream stream = StreamSupport.stream(spliterator, false); return stream.map(doc -> new MongoDbRow(doc, context())); } diff --git a/dbclient/mongodb/src/test/java/io/helidon/dbclient/mongodb/MongoDbClientTest.java b/dbclient/mongodb/src/test/java/io/helidon/dbclient/mongodb/MongoDbClientTest.java index ca9e361ea4d..4bb5daa1ea0 100644 --- a/dbclient/mongodb/src/test/java/io/helidon/dbclient/mongodb/MongoDbClientTest.java +++ b/dbclient/mongodb/src/test/java/io/helidon/dbclient/mongodb/MongoDbClientTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. + * Copyright (c) 2021, 2024 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. @@ -16,34 +16,39 @@ package io.helidon.dbclient.mongodb; import java.lang.System.Logger.Level; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.function.Consumer; +import io.helidon.dbclient.DbClientService; +import io.helidon.dbclient.DbClientServiceContext; import io.helidon.dbclient.DbExecute; import com.mongodb.client.MongoClient; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; +import org.bson.Document; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.mockito.Mockito; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; -public class MongoDbClientTest { +@SuppressWarnings("resource") +class MongoDbClientTest { private static final System.Logger LOGGER = System.getLogger(MongoDbClientTest.class.getName()); private static MongoDbClient dbClient; @BeforeAll static void setup() { - MongoClient client = Mockito.mock(MongoClient.class); - MongoDatabase db = Mockito.mock(MongoDatabase.class); - when(db.runCommand(any())).thenReturn(MongoDbStatement.EMPTY); - dbClient = new MongoDbClient(new MongoDbClientBuilder(), client, db); + dbClient = createClient(null); } @Test @@ -85,4 +90,70 @@ void testUnsupportedUnwrapExecutorClass() { exec.query("{\"operation\": \"command\", \"query\": { ping: 1 }}"); } + @Test + void testDbClientServiceQuery() { + TestDbClientService service = new TestDbClientService(); + MongoDbClient dbClient = createClient(builder -> builder.addService(service)); + DbExecute exec = dbClient.execute(); + long ignored = exec.query("{\"operation\": \"command\", \"query\": { ping: 1 }}").count(); + assertThat(service.resultFuture.isDone(), is(true)); + assertThat(service.resultFuture.isCompletedExceptionally(), is(false)); + assertThat(service.statementFuture.isDone(), is(true)); + assertThat(service.statementFuture.isCompletedExceptionally(), is(false)); + } + + @Test + void testDbClientServiceDml() { + TestDbClientService service = new TestDbClientService(); + MongoDbClient dbClient = createClient(builder -> builder.addService(service)); + DbExecute exec = dbClient.execute(); + long ignored = exec.insert("{" + + "\"collection\": \"foo\"," + + "\"operation\": \"insert\"," + + "\"value\": { \"name\": \"bar\" }" + + "}"); + assertThat(service.resultFuture.isDone(), is(true)); + assertThat(service.resultFuture.isCompletedExceptionally(), is(false)); + assertThat(service.statementFuture.isDone(), is(true)); + assertThat(service.statementFuture.isCompletedExceptionally(), is(false)); + } + + @SuppressWarnings("unchecked") + static MongoDbClient createClient(Consumer consumer) { + MongoClient client = Mockito.mock(MongoClient.class); + MongoDatabase db = Mockito.mock(MongoDatabase.class); + MongoCollection collection = Mockito.mock(MongoCollection.class); + when(db.getCollection(any())).thenReturn(collection); + when(db.runCommand(any())).thenReturn(MongoDbStatement.EMPTY); + MongoDbClientBuilder builder = new MongoDbClientBuilder(); + if (consumer != null) { + consumer.accept(builder); + } + return new MongoDbClient(builder, client, db); + } + + record TestDbClientService(CompletableFuture resultFuture, + CompletableFuture statementFuture) implements DbClientService { + + TestDbClientService() { + this(new CompletableFuture<>(), new CompletableFuture<>()); + } + + @Override + public DbClientServiceContext statement(DbClientServiceContext context) { + setup(context.resultFuture(), resultFuture); + setup(context.statementFuture(), statementFuture); + return context; + } + + static void setup(CompletionStage stage, CompletableFuture future) { + stage.whenComplete((v, ex) -> { + if (ex != null) { + future.completeExceptionally(ex); + } else { + future.complete(v); + } + }); + } + } } From 7c05a741c4ff0f540e3cfcd76053758e49e58880 Mon Sep 17 00:00:00 2001 From: Romain Grecourt Date: Mon, 5 Aug 2024 17:09:34 -0700 Subject: [PATCH 32/37] Generate config docs during build (#9103) - Inline io_helidon_microprofile_lra_Coordinator.adoc in mp/lra.adoc - Delete all generated config docs - Add a .gitignore under docs to ignore src/main/asciidoc/config - Execute the config doc generator by default - Configure the default-clean execution to remove src/main/asciidoc/config/**/* - Remove configdocs profile - Configure compiler-plugin to disable removal warning - Update ConfigDocs (generator) to create the target directory if it does not exist Fixes #9056 --- .../config/metadata/docs/ConfigDocs.java | 30 ++- docs/.gitignore | 1 + docs/pom.xml | 78 +++--- .../asciidoc/config/config_reference.adoc | 144 ---------- ...helidon_common_configurable_AllowList.adoc | 77 ------ ..._helidon_common_configurable_LruCache.adoc | 51 ---- ..._helidon_common_configurable_Resource.adoc | 78 ------ ...onfigurable_ScheduledThreadPoolConfig.adoc | 69 ----- ...figurable_ScheduledThreadPoolSupplier.adoc | 69 ----- ..._common_configurable_ThreadPoolConfig.adoc | 101 ------- ...ommon_configurable_ThreadPoolSupplier.adoc | 101 ------- .../config/io_helidon_common_pki_Keys.adoc | 58 ---- .../io_helidon_common_pki_KeystoreKeys.adoc | 86 ------ .../config/io_helidon_common_pki_PemKeys.adoc | 64 ----- ...o_helidon_common_socket_SocketOptions.adoc | 77 ------ ...o_helidon_common_tls_RevocationConfig.adoc | 83 ------ .../config/io_helidon_common_tls_Tls.adoc | 132 ---------- .../io_helidon_config_mp_MpConfigBuilder.adoc | 51 ---- .../io_helidon_cors_CrossOriginConfig.adoc | 56 ---- ...on_dbclient_jdbc_JdbcParametersConfig.adoc | 90 ------- .../io_helidon_faulttolerance_Async.adoc | 52 ---- .../io_helidon_faulttolerance_Bulkhead.adoc | 59 ----- ...helidon_faulttolerance_CircuitBreaker.adoc | 70 ----- .../io_helidon_faulttolerance_Retry.adoc | 71 ----- .../io_helidon_faulttolerance_Timeout.adoc | 58 ---- ...don_http_RequestedUriDiscoveryContext.adoc | 64 ----- ..._http_encoding_ContentEncodingContext.adoc | 52 ---- .../io_helidon_http_media_MediaContext.adoc | 60 ----- ...grations_micrometer_MicrometerFeature.adoc | 56 ---- .../io_helidon_integrations_neo4j_Neo4j.adoc | 69 ----- ...tegrations_oci_ConfigFileMethodConfig.adoc | 54 ---- ...n_integrations_oci_ConfigMethodConfig.adoc | 82 ------ ...don_integrations_oci_ImdsInstanceInfo.adoc | 75 ------ ...io_helidon_integrations_oci_OciConfig.adoc | 110 -------- ...grations_oci_SessionTokenMethodConfig.adoc | 105 -------- ...rations_oci_metrics_OciMetricsSupport.adoc | 72 ----- ...ntegrations_oci_sdk_runtime_OciConfig.adoc | 197 -------------- ...ertificates_OciCertificatesTlsManager.adoc | 76 ------ ...don_integrations_openapi_ui_OpenApiUi.adoc | 57 ---- ..._metrics_api_ComponentMetricsSettings.adoc | 55 ---- ..._KeyPerformanceIndicatorMetricsConfig.adoc | 54 ---- .../io_helidon_metrics_api_MetricsConfig.adoc | 92 ------- .../io_helidon_metrics_api_ScopeConfig.adoc | 60 ----- .../io_helidon_metrics_api_ScopingConfig.adoc | 58 ---- .../config/io_helidon_metrics_api_Tag.adoc | 39 --- ...microprofile_jwt_auth_JwtAuthProvider.adoc | 90 ------- ..._helidon_microprofile_lra_Coordinator.adoc | 51 ---- ...rofile_openapi_MpOpenApiManagerConfig.adoc | 52 ---- ...io_helidon_microprofile_server_Server.adoc | 54 ---- .../io_helidon_openapi_OpenApiFeature.adoc | 86 ------ .../config/io_helidon_scheduling_Cron.adoc | 69 ----- .../io_helidon_scheduling_FixedRate.adoc | 82 ------ .../io_helidon_scheduling_TaskConfig.adoc | 39 --- .../config/io_helidon_security_Security.adoc | 106 -------- .../io_helidon_security_SecurityTime.adoc | 60 ----- ..._security_providers_abac_AbacProvider.adoc | 63 ----- ...urity_providers_common_EvictableCache.adoc | 59 ----- ...urity_providers_common_OutboundConfig.adoc | 51 ---- ...urity_providers_common_OutboundTarget.adoc | 87 ------ ...ders_config_vault_ConfigVaultProvider.adoc | 64 ----- ...ault_ConfigVaultProvider_SecretConfig.adoc | 55 ---- ...ders_google_login_GoogleTokenProvider.adoc | 70 ----- ...ty_providers_header_HeaderAtnProvider.adoc | 71 ----- ...s_httpauth_ConfigUserStore_ConfigUser.adoc | 51 ---- ...viders_httpauth_HttpBasicAuthProvider.adoc | 69 ----- ...iders_httpauth_HttpDigestAuthProvider.adoc | 89 ------- ...y_providers_httpsign_HttpSignProvider.adoc | 150 ----------- ...ders_httpsign_InboundClientDefinition.adoc | 61 ----- ...ign_SignedHeadersConfig_HeadersConfig.adoc | 51 ---- ..._idcs_mapper_IdcsMtRoleMapperProvider.adoc | 76 ------ ...rs_idcs_mapper_IdcsRoleMapperProvider.adoc | 72 ----- ...er_IdcsRoleMapperProviderBase_Builder.adoc | 58 ---- ...on_security_providers_jwt_JwtProvider.adoc | 90 ------- ..._security_providers_oidc_OidcProvider.adoc | 249 ------------------ ...ity_providers_oidc_common_BaseBuilder.adoc | 132 ---------- ...rity_providers_oidc_common_OidcConfig.adoc | 231 ---------------- ...ty_providers_oidc_common_TenantConfig.adoc | 143 ---------- ...io_helidon_security_util_TokenHandler.adoc | 52 ---- .../config/io_helidon_tracing_Tracer.adoc | 86 ------ .../io_helidon_tracing_TracerBuilder.adoc | 41 --- ..._providers_jaeger_JaegerTracerBuilder.adoc | 86 ------ ..._opentracing_OpenTracingTracerBuilder.adoc | 41 --- ..._providers_zipkin_ZipkinTracerBuilder.adoc | 60 ----- ...elidon_webclient_api_HttpClientConfig.adoc | 141 ---------- ..._helidon_webclient_api_HttpConfigBase.adoc | 80 ------ .../io_helidon_webclient_api_Proxy.adoc | 72 ----- .../io_helidon_webclient_api_WebClient.adoc | 146 ---------- ..._webclient_api_WebClientCookieManager.adoc | 57 ---- .../io_helidon_webclient_grpc_GrpcClient.adoc | 51 ---- ...bclient_grpc_GrpcClientProtocolConfig.adoc | 71 ----- ...lient_http1_Http1ClientProtocolConfig.adoc | 71 ----- ...lient_http2_Http2ClientProtocolConfig.adoc | 93 ------- ..._helidon_webclient_websocket_WsClient.adoc | 51 ---- ...ient_websocket_WsClientProtocolConfig.adoc | 50 ---- ...io_helidon_webserver_ConnectionConfig.adoc | 83 ------ .../io_helidon_webserver_ListenerConfig.adoc | 165 ------------ .../io_helidon_webserver_WebServer.adoc | 191 -------------- ...n_webserver_accesslog_AccessLogConfig.adoc | 133 ---------- ..._webserver_accesslog_AccessLogFeature.adoc | 133 ---------- ...idon_webserver_context_ContextFeature.adoc | 65 ----- .../io_helidon_webserver_cors_CorsConfig.adoc | 76 ------ ...io_helidon_webserver_cors_CorsFeature.adoc | 76 ------ .../io_helidon_webserver_grpc_GrpcConfig.adoc | 49 ---- ...idon_webserver_grpc_GrpcTracingConfig.adoc | 51 ---- ...o_helidon_webserver_http1_Http1Config.adoc | 102 ------- ...o_helidon_webserver_http2_Http2Config.adoc | 128 --------- ...idon_webserver_observe_ObserveFeature.adoc | 96 ------- ..._webserver_observe_ObserverConfigBase.adoc | 51 ---- ...bserver_observe_config_ConfigObserver.adoc | 72 ----- ...bserver_observe_health_HealthObserver.adoc | 68 ----- ...n_webserver_observe_info_InfoObserver.adoc | 62 ----- ...don_webserver_observe_log_LogObserver.adoc | 65 ----- ...webserver_observe_log_LogStreamConfig.adoc | 65 ----- ...erver_observe_metrics_MetricsObserver.adoc | 97 ------- ...erver_observe_tracing_TracingObserver.adoc | 92 ------- ...elidon_webserver_security_PathsConfig.adoc | 89 ------- ...on_webserver_security_SecurityFeature.adoc | 76 ------ ...on_webserver_security_SecurityHandler.adoc | 86 ------ ...ecommon_HelidonFeatureSupport_Builder.adoc | 50 ---- ...ver_servicecommon_RestServiceSettings.adoc | 52 ---- ..._helidon_webserver_websocket_WsConfig.adoc | 68 ----- .../config/io_opentracing_Tracer.adoc | 60 ----- ...rg_eclipse_microprofile_config_Config.adoc | 51 ---- docs/src/main/asciidoc/mp/lra.adoc | 23 +- 124 files changed, 85 insertions(+), 9663 deletions(-) create mode 100644 docs/.gitignore delete mode 100644 docs/src/main/asciidoc/config/config_reference.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_common_configurable_AllowList.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_common_configurable_LruCache.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_common_configurable_Resource.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_common_configurable_ScheduledThreadPoolConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_common_configurable_ScheduledThreadPoolSupplier.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_common_configurable_ThreadPoolConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_common_configurable_ThreadPoolSupplier.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_common_pki_Keys.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_common_pki_KeystoreKeys.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_common_pki_PemKeys.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_common_socket_SocketOptions.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_common_tls_RevocationConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_common_tls_Tls.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_config_mp_MpConfigBuilder.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_cors_CrossOriginConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_dbclient_jdbc_JdbcParametersConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_faulttolerance_Async.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_faulttolerance_Bulkhead.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_faulttolerance_CircuitBreaker.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_faulttolerance_Retry.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_faulttolerance_Timeout.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_http_RequestedUriDiscoveryContext.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_http_encoding_ContentEncodingContext.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_http_media_MediaContext.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_integrations_micrometer_MicrometerFeature.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_integrations_neo4j_Neo4j.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_integrations_oci_ConfigFileMethodConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_integrations_oci_ConfigMethodConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_integrations_oci_ImdsInstanceInfo.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_integrations_oci_OciConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_integrations_oci_SessionTokenMethodConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_integrations_oci_metrics_OciMetricsSupport.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_integrations_oci_sdk_runtime_OciConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_integrations_oci_tls_certificates_OciCertificatesTlsManager.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_integrations_openapi_ui_OpenApiUi.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_metrics_api_ComponentMetricsSettings.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_metrics_api_KeyPerformanceIndicatorMetricsConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_metrics_api_MetricsConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_metrics_api_ScopeConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_metrics_api_ScopingConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_metrics_api_Tag.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_microprofile_jwt_auth_JwtAuthProvider.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_microprofile_lra_Coordinator.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_microprofile_openapi_MpOpenApiManagerConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_microprofile_server_Server.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_openapi_OpenApiFeature.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_scheduling_Cron.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_scheduling_FixedRate.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_scheduling_TaskConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_security_Security.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_security_SecurityTime.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_security_providers_abac_AbacProvider.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_security_providers_common_EvictableCache.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_security_providers_common_OutboundConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_security_providers_common_OutboundTarget.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_security_providers_config_vault_ConfigVaultProvider.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_security_providers_config_vault_ConfigVaultProvider_SecretConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_security_providers_google_login_GoogleTokenProvider.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_security_providers_header_HeaderAtnProvider.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_security_providers_httpauth_ConfigUserStore_ConfigUser.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_security_providers_httpauth_HttpBasicAuthProvider.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_security_providers_httpauth_HttpDigestAuthProvider.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_security_providers_httpsign_HttpSignProvider.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_security_providers_httpsign_InboundClientDefinition.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_security_providers_httpsign_SignedHeadersConfig_HeadersConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_security_providers_idcs_mapper_IdcsMtRoleMapperProvider.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_security_providers_idcs_mapper_IdcsRoleMapperProvider.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_security_providers_idcs_mapper_IdcsRoleMapperProviderBase_Builder.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_security_providers_jwt_JwtProvider.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_OidcProvider.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_common_BaseBuilder.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_common_OidcConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_common_TenantConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_security_util_TokenHandler.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_tracing_Tracer.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_tracing_TracerBuilder.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_tracing_providers_jaeger_JaegerTracerBuilder.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_tracing_providers_opentracing_OpenTracingTracerBuilder.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_tracing_providers_zipkin_ZipkinTracerBuilder.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webclient_api_HttpClientConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webclient_api_HttpConfigBase.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webclient_api_Proxy.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webclient_api_WebClient.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webclient_api_WebClientCookieManager.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webclient_grpc_GrpcClient.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webclient_grpc_GrpcClientProtocolConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webclient_http1_Http1ClientProtocolConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webclient_http2_Http2ClientProtocolConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webclient_websocket_WsClient.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webclient_websocket_WsClientProtocolConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webserver_ConnectionConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webserver_ListenerConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webserver_WebServer.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webserver_accesslog_AccessLogConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webserver_accesslog_AccessLogFeature.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webserver_context_ContextFeature.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webserver_cors_CorsConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webserver_cors_CorsFeature.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webserver_grpc_GrpcConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webserver_grpc_GrpcTracingConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webserver_http1_Http1Config.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webserver_http2_Http2Config.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webserver_observe_ObserveFeature.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webserver_observe_ObserverConfigBase.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webserver_observe_config_ConfigObserver.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webserver_observe_health_HealthObserver.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webserver_observe_info_InfoObserver.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webserver_observe_log_LogObserver.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webserver_observe_log_LogStreamConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webserver_observe_metrics_MetricsObserver.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webserver_observe_tracing_TracingObserver.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webserver_security_PathsConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webserver_security_SecurityFeature.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webserver_security_SecurityHandler.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webserver_servicecommon_HelidonFeatureSupport_Builder.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webserver_servicecommon_RestServiceSettings.adoc delete mode 100644 docs/src/main/asciidoc/config/io_helidon_webserver_websocket_WsConfig.adoc delete mode 100644 docs/src/main/asciidoc/config/io_opentracing_Tracer.adoc delete mode 100644 docs/src/main/asciidoc/config/org_eclipse_microprofile_config_Config.adoc diff --git a/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/ConfigDocs.java b/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/ConfigDocs.java index 1ed530f5a2f..2f8d3c6a842 100644 --- a/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/ConfigDocs.java +++ b/config/metadata/docs/src/main/java/io/helidon/config/metadata/docs/ConfigDocs.java @@ -595,27 +595,31 @@ private static String mapAllowedValues(CmOption option, String displayType) { + " (" + values.stream().map(CmAllowedValue::getValue).collect(Collectors.joining(", ")) + ")"; } - // the target path must either contain zero files, or the config reference - // and it must exist + // if the target path exists, it must either contain zero files, or the config reference private void checkTargetPath(Path configReference) throws IOException { - if (Files.exists(path) && Files.isDirectory(path)) { - // either empty, or contains config reference - if (Files.exists(configReference) && Files.isRegularFile(configReference)) { - return; - } + // contains config reference + if (Files.exists(configReference) && Files.isRegularFile(configReference)) { + return; + } + if (!Files.exists(path)) { + Files.createDirectories(path); + return; + } + if (Files.isDirectory(path)) { // must be empty try (Stream stream = Files.list(path)) { if (stream.findAny() .isPresent()) { - throw new ConfigDocsException("Cannot generate config reference documentation, unless target path contains " - + CONFIG_REFERENCE_ADOC + " file or it is empty. " - + "Target path: " + path.toAbsolutePath() + " contains files"); + throw new ConfigDocsException( + "Cannot generate config reference documentation, unless target path contains " + + CONFIG_REFERENCE_ADOC + " file or it is empty. " + + "Target path: " + path.toAbsolutePath() + " contains files"); } } } else { - throw new IllegalArgumentException("Target path must be a directory and must exist: " - + path.toAbsolutePath().normalize()); + throw new IllegalArgumentException("Target path must be a directory: " + + path.toAbsolutePath().normalize()); } } @@ -624,8 +628,6 @@ private Template template(Handlebars handlebars, String template) { if (resource == null) { throw new ConfigDocsException("Failed to locate required handlebars template on classpath: " + template); } - Template typeTemplate; - Template configReferenceTemplate; try { return handlebars.compile(new URLTemplateSource(template, resource)); } catch (IOException e) { diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 00000000000..3b941ae837f --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +src/main/asciidoc/config diff --git a/docs/pom.xml b/docs/pom.xml index feebb6ebea1..c9c3f3d5583 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -52,6 +52,7 @@ mockito-core + org.apache.activemq activemq-client @@ -98,6 +99,46 @@ ${project.artifactId} + + org.apache.maven.plugins + maven-clean-plugin + + + default-clean + + + + src/main/asciidoc/config + + **/* + + + + + + + + + org.codehaus.mojo + exec-maven-plugin + + + config-docs + + java + + generate-sources + + ${project.basedir}/src/main/asciidoc/config + io.helidon.config.metadata.docs.Main + + helidon-logging-slf4j-${helidon.version}.jar + helidon-logging-log4j-${helidon.version}.jar + + + + + io.helidon.build-tools sitegen-maven-plugin @@ -114,6 +155,9 @@ maven-compiler-plugin none + + -Xlint:-removal + @@ -129,34 +173,6 @@ - - configdoc - - - - org.codehaus.mojo - exec-maven-plugin - - - regenerate-config-docs - - java - - generate-sources - - - - ${project.basedir}/src/main/asciidoc/config - io.helidon.config.metadata.docs.Main - - helidon-logging-slf4j-${helidon.version}.jar - helidon-logging-log4j-${helidon.version}.jar - - - - - - javadoc @@ -221,9 +237,9 @@ io.helidon.inject* *.processor* - io.helidon.integrations.oci.authentication.instance - io.helidon.integrations.oci.authentication.resource - io.helidon.integrations.oci.authentication.okeworkload + io.helidon.integrations.oci.authentication.instance + io.helidon.integrations.oci.authentication.resource + io.helidon.integrations.oci.authentication.okeworkload io.helidon* diff --git a/docs/src/main/asciidoc/config/config_reference.adoc b/docs/src/main/asciidoc/config/config_reference.adoc deleted file mode 100644 index a0a05104fc4..00000000000 --- a/docs/src/main/asciidoc/config/config_reference.adoc +++ /dev/null @@ -1,144 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2022, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration Reference -:keywords: helidon, config, reference - -= Configuration Reference - -The following section lists all configurable types in Helidon. - -- xref:{rootdir}/config/io_helidon_security_providers_abac_AbacProvider.adoc[AbacProvider (security.providers.abac)] -- xref:{rootdir}/config/io_helidon_webserver_accesslog_AccessLogConfig.adoc[AccessLogConfig (webserver.accesslog)] -- xref:{rootdir}/config/io_helidon_webserver_accesslog_AccessLogFeature.adoc[AccessLogFeature (webserver.accesslog)] -- xref:{rootdir}/config/io_helidon_common_configurable_AllowList.adoc[AllowList (common.configurable)] -- xref:{rootdir}/config/io_helidon_faulttolerance_Async.adoc[Async (faulttolerance)] -- xref:{rootdir}/config/io_helidon_security_providers_oidc_common_BaseBuilder.adoc[BaseBuilder (security.providers.oidc.common)] -- xref:{rootdir}/config/io_helidon_security_providers_idcs_mapper_IdcsRoleMapperProviderBase_Builder.adoc[Builder (security.providers.idcs.mapper.IdcsRoleMapperProviderBase)] -- xref:{rootdir}/config/io_helidon_webserver_servicecommon_HelidonFeatureSupport_Builder.adoc[Builder (webserver.servicecommon.HelidonFeatureSupport)] -- xref:{rootdir}/config/io_helidon_faulttolerance_Bulkhead.adoc[Bulkhead (faulttolerance)] -- xref:{rootdir}/config/io_helidon_faulttolerance_CircuitBreaker.adoc[CircuitBreaker (faulttolerance)] -- xref:{rootdir}/config/io_helidon_metrics_api_ComponentMetricsSettings.adoc[ComponentMetricsSettings (metrics.api)] -- xref:{rootdir}/config/io_helidon_integrations_oci_ConfigFileMethodConfig.adoc[ConfigFileMethodConfig (integrations.oci)] -- xref:{rootdir}/config/io_helidon_integrations_oci_ConfigMethodConfig.adoc[ConfigMethodConfig (integrations.oci)] -- xref:{rootdir}/config/io_helidon_webserver_observe_config_ConfigObserver.adoc[ConfigObserver (webserver.observe.config)] -- xref:{rootdir}/config/io_helidon_security_providers_httpauth_ConfigUserStore_ConfigUser.adoc[ConfigUser (security.providers.httpauth.ConfigUserStore)] -- xref:{rootdir}/config/io_helidon_security_providers_config_vault_ConfigVaultProvider.adoc[ConfigVaultProvider (security.providers.config.vault)] -- xref:{rootdir}/config/io_helidon_webserver_ConnectionConfig.adoc[ConnectionConfig (webserver)] -- xref:{rootdir}/config/io_helidon_http_encoding_ContentEncodingContext.adoc[ContentEncodingContext (http.encoding)] -- xref:{rootdir}/config/io_helidon_webserver_context_ContextFeature.adoc[ContextFeature (webserver.context)] -- xref:{rootdir}/config/io_helidon_webserver_cors_CorsConfig.adoc[CorsConfig (webserver.cors)] -- xref:{rootdir}/config/io_helidon_webserver_cors_CorsFeature.adoc[CorsFeature (webserver.cors)] -- xref:{rootdir}/config/io_helidon_scheduling_Cron.adoc[Cron (scheduling)] -- xref:{rootdir}/config/io_helidon_cors_CrossOriginConfig.adoc[CrossOriginConfig (cors)] -- xref:{rootdir}/config/io_helidon_security_providers_common_EvictableCache.adoc[EvictableCache (security.providers.common)] -- xref:{rootdir}/config/io_helidon_scheduling_FixedRate.adoc[FixedRate (scheduling)] -- xref:{rootdir}/config/io_helidon_security_providers_google_login_GoogleTokenProvider.adoc[GoogleTokenProvider (security.providers.google.login)] -- xref:{rootdir}/config/io_helidon_webclient_grpc_GrpcClient.adoc[GrpcClient (webclient.grpc)] -- xref:{rootdir}/config/io_helidon_webclient_grpc_GrpcClientProtocolConfig.adoc[GrpcClientProtocolConfig (webclient.grpc)] -- xref:{rootdir}/config/io_helidon_webserver_grpc_GrpcConfig.adoc[GrpcConfig (webserver.grpc)] -- xref:{rootdir}/config/io_helidon_webserver_grpc_GrpcTracingConfig.adoc[GrpcTracingConfig (webserver.grpc)] -- xref:{rootdir}/config/io_helidon_security_providers_header_HeaderAtnProvider.adoc[HeaderAtnProvider (security.providers.header)] -- xref:{rootdir}/config/io_helidon_security_providers_httpsign_SignedHeadersConfig_HeadersConfig.adoc[HeadersConfig (security.providers.httpsign.SignedHeadersConfig)] -- xref:{rootdir}/config/io_helidon_webserver_observe_health_HealthObserver.adoc[HealthObserver (webserver.observe.health)] -- xref:{rootdir}/config/io_helidon_webclient_http1_Http1ClientProtocolConfig.adoc[Http1ClientProtocolConfig (webclient.http1)] -- xref:{rootdir}/config/io_helidon_webserver_http1_Http1Config.adoc[Http1Config (webserver.http1)] -- xref:{rootdir}/config/io_helidon_webclient_http2_Http2ClientProtocolConfig.adoc[Http2ClientProtocolConfig (webclient.http2)] -- xref:{rootdir}/config/io_helidon_webserver_http2_Http2Config.adoc[Http2Config (webserver.http2)] -- xref:{rootdir}/config/io_helidon_security_providers_httpauth_HttpBasicAuthProvider.adoc[HttpBasicAuthProvider (security.providers.httpauth)] -- xref:{rootdir}/config/io_helidon_webclient_api_HttpClientConfig.adoc[HttpClientConfig (webclient.api)] -- xref:{rootdir}/config/io_helidon_webclient_api_HttpConfigBase.adoc[HttpConfigBase (webclient.api)] -- xref:{rootdir}/config/io_helidon_security_providers_httpauth_HttpDigestAuthProvider.adoc[HttpDigestAuthProvider (security.providers.httpauth)] -- xref:{rootdir}/config/io_helidon_security_providers_httpsign_HttpSignProvider.adoc[HttpSignProvider (security.providers.httpsign)] -- xref:{rootdir}/config/io_helidon_security_providers_idcs_mapper_IdcsMtRoleMapperProvider.adoc[IdcsMtRoleMapperProvider (security.providers.idcs.mapper)] -- xref:{rootdir}/config/io_helidon_security_providers_idcs_mapper_IdcsRoleMapperProvider.adoc[IdcsRoleMapperProvider (security.providers.idcs.mapper)] -- xref:{rootdir}/config/io_helidon_integrations_oci_ImdsInstanceInfo.adoc[ImdsInstanceInfo (integrations.oci)] -- xref:{rootdir}/config/io_helidon_security_providers_httpsign_InboundClientDefinition.adoc[InboundClientDefinition (security.providers.httpsign)] -- xref:{rootdir}/config/io_helidon_webserver_observe_info_InfoObserver.adoc[InfoObserver (webserver.observe.info)] -- xref:{rootdir}/config/io_helidon_tracing_providers_jaeger_JaegerTracerBuilder.adoc[JaegerTracerBuilder (tracing.providers.jaeger)] -- xref:{rootdir}/config/io_helidon_dbclient_jdbc_JdbcParametersConfig.adoc[JdbcParametersConfig (dbclient.jdbc)] -- xref:{rootdir}/config/io_helidon_microprofile_jwt_auth_JwtAuthProvider.adoc[JwtAuthProvider (microprofile.jwt.auth)] -- xref:{rootdir}/config/io_helidon_security_providers_jwt_JwtProvider.adoc[JwtProvider (security.providers.jwt)] -- xref:{rootdir}/config/io_helidon_metrics_api_KeyPerformanceIndicatorMetricsConfig.adoc[KeyPerformanceIndicatorMetricsConfig (metrics.api)] -- xref:{rootdir}/config/io_helidon_common_pki_Keys.adoc[Keys (common.pki)] -- xref:{rootdir}/config/io_helidon_common_pki_KeystoreKeys.adoc[KeystoreKeys (common.pki)] -- xref:{rootdir}/config/io_helidon_webserver_ListenerConfig.adoc[ListenerConfig (webserver)] -- xref:{rootdir}/config/io_helidon_webserver_observe_log_LogObserver.adoc[LogObserver (webserver.observe.log)] -- xref:{rootdir}/config/io_helidon_webserver_observe_log_LogStreamConfig.adoc[LogStreamConfig (webserver.observe.log)] -- xref:{rootdir}/config/io_helidon_common_configurable_LruCache.adoc[LruCache (common.configurable)] -- xref:{rootdir}/config/io_helidon_http_media_MediaContext.adoc[MediaContext (http.media)] -- xref:{rootdir}/config/io_helidon_metrics_api_MetricsConfig.adoc[MetricsConfig (metrics.api)] -- xref:{rootdir}/config/io_helidon_webserver_observe_metrics_MetricsObserver.adoc[MetricsObserver (webserver.observe.metrics)] -- xref:{rootdir}/config/io_helidon_integrations_micrometer_MicrometerFeature.adoc[MicrometerFeature (integrations.micrometer)] -- xref:{rootdir}/config/io_helidon_config_mp_MpConfigBuilder.adoc[MpConfigBuilder (config.mp)] -- xref:{rootdir}/config/io_helidon_microprofile_openapi_MpOpenApiManagerConfig.adoc[MpOpenApiManagerConfig (microprofile.openapi)] -- xref:{rootdir}/config/io_helidon_integrations_neo4j_Neo4j.adoc[Neo4j (integrations.neo4j)] -- xref:{rootdir}/config/io_helidon_webserver_observe_ObserveFeature.adoc[ObserveFeature (webserver.observe)] -- xref:{rootdir}/config/io_helidon_webserver_observe_ObserverConfigBase.adoc[ObserverConfigBase (webserver.observe)] -- xref:{rootdir}/config/io_helidon_integrations_oci_tls_certificates_OciCertificatesTlsManager.adoc[OciCertificatesTlsManager (integrations.oci.tls.certificates)] -- xref:{rootdir}/config/io_helidon_integrations_oci_OciConfig.adoc[OciConfig (integrations.oci)] -- xref:{rootdir}/config/io_helidon_integrations_oci_sdk_runtime_OciConfig.adoc[OciConfig (integrations.oci.sdk.runtime)] -- xref:{rootdir}/config/io_helidon_integrations_oci_metrics_OciMetricsSupport.adoc[OciMetricsSupport (integrations.oci.metrics)] -- xref:{rootdir}/config/io_helidon_security_providers_oidc_common_OidcConfig.adoc[OidcConfig (security.providers.oidc.common)] -- xref:{rootdir}/config/io_helidon_security_providers_oidc_OidcProvider.adoc[OidcProvider (security.providers.oidc)] -- xref:{rootdir}/config/io_helidon_openapi_OpenApiFeature.adoc[OpenApiFeature (openapi)] -- xref:{rootdir}/config/io_helidon_integrations_openapi_ui_OpenApiUi.adoc[OpenApiUi (integrations.openapi.ui)] -- xref:{rootdir}/config/io_helidon_tracing_providers_opentracing_OpenTracingTracerBuilder.adoc[OpenTracingTracerBuilder (tracing.providers.opentracing)] -- xref:{rootdir}/config/io_helidon_security_providers_common_OutboundConfig.adoc[OutboundConfig (security.providers.common)] -- xref:{rootdir}/config/io_helidon_security_providers_common_OutboundTarget.adoc[OutboundTarget (security.providers.common)] -- xref:{rootdir}/config/io_helidon_webserver_security_PathsConfig.adoc[PathsConfig (webserver.security)] -- xref:{rootdir}/config/io_helidon_common_pki_PemKeys.adoc[PemKeys (common.pki)] -- xref:{rootdir}/config/io_helidon_webclient_api_Proxy.adoc[Proxy (webclient.api)] -- xref:{rootdir}/config/io_helidon_http_RequestedUriDiscoveryContext.adoc[RequestedUriDiscoveryContext (http)] -- xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource (common.configurable)] -- xref:{rootdir}/config/io_helidon_webserver_servicecommon_RestServiceSettings.adoc[RestServiceSettings (webserver.servicecommon)] -- xref:{rootdir}/config/io_helidon_faulttolerance_Retry.adoc[Retry (faulttolerance)] -- xref:{rootdir}/config/io_helidon_common_tls_RevocationConfig.adoc[RevocationConfig (common.tls)] -- xref:{rootdir}/config/io_helidon_common_configurable_ScheduledThreadPoolConfig.adoc[ScheduledThreadPoolConfig (common.configurable)] -- xref:{rootdir}/config/io_helidon_common_configurable_ScheduledThreadPoolSupplier.adoc[ScheduledThreadPoolSupplier (common.configurable)] -- xref:{rootdir}/config/io_helidon_metrics_api_ScopeConfig.adoc[ScopeConfig (metrics.api)] -- xref:{rootdir}/config/io_helidon_metrics_api_ScopingConfig.adoc[ScopingConfig (metrics.api)] -- xref:{rootdir}/config/io_helidon_security_providers_config_vault_ConfigVaultProvider_SecretConfig.adoc[SecretConfig (security.providers.config.vault.ConfigVaultProvider)] -- xref:{rootdir}/config/io_helidon_security_Security.adoc[Security (security)] -- xref:{rootdir}/config/io_helidon_webserver_security_SecurityFeature.adoc[SecurityFeature (webserver.security)] -- xref:{rootdir}/config/io_helidon_webserver_security_SecurityHandler.adoc[SecurityHandler (webserver.security)] -- xref:{rootdir}/config/io_helidon_security_SecurityTime.adoc[SecurityTime (security)] -- xref:{rootdir}/config/io_helidon_microprofile_server_Server.adoc[Server (microprofile.server)] -- xref:{rootdir}/config/io_helidon_integrations_oci_SessionTokenMethodConfig.adoc[SessionTokenMethodConfig (integrations.oci)] -- xref:{rootdir}/config/io_helidon_common_socket_SocketOptions.adoc[SocketOptions (common.socket)] -- xref:{rootdir}/config/io_helidon_metrics_api_Tag.adoc[Tag (metrics.api)] -- xref:{rootdir}/config/io_helidon_scheduling_TaskConfig.adoc[TaskConfig (scheduling)] -- xref:{rootdir}/config/io_helidon_security_providers_oidc_common_TenantConfig.adoc[TenantConfig (security.providers.oidc.common)] -- xref:{rootdir}/config/io_helidon_common_configurable_ThreadPoolConfig.adoc[ThreadPoolConfig (common.configurable)] -- xref:{rootdir}/config/io_helidon_common_configurable_ThreadPoolSupplier.adoc[ThreadPoolSupplier (common.configurable)] -- xref:{rootdir}/config/io_helidon_faulttolerance_Timeout.adoc[Timeout (faulttolerance)] -- xref:{rootdir}/config/io_helidon_common_tls_Tls.adoc[Tls (common.tls)] -- xref:{rootdir}/config/io_helidon_security_util_TokenHandler.adoc[TokenHandler (security.util)] -- xref:{rootdir}/config/io_helidon_tracing_Tracer.adoc[Tracer (tracing)] -- xref:{rootdir}/config/io_helidon_tracing_TracerBuilder.adoc[TracerBuilder (tracing)] -- xref:{rootdir}/config/io_helidon_webserver_observe_tracing_TracingObserver.adoc[TracingObserver (webserver.observe.tracing)] -- xref:{rootdir}/config/io_helidon_webclient_api_WebClient.adoc[WebClient (webclient.api)] -- xref:{rootdir}/config/io_helidon_webclient_api_WebClientCookieManager.adoc[WebClientCookieManager (webclient.api)] -- xref:{rootdir}/config/io_helidon_webserver_WebServer.adoc[WebServer (webserver)] -- xref:{rootdir}/config/io_helidon_webclient_websocket_WsClient.adoc[WsClient (webclient.websocket)] -- xref:{rootdir}/config/io_helidon_webclient_websocket_WsClientProtocolConfig.adoc[WsClientProtocolConfig (webclient.websocket)] -- xref:{rootdir}/config/io_helidon_webserver_websocket_WsConfig.adoc[WsConfig (webserver.websocket)] -- xref:{rootdir}/config/io_helidon_tracing_providers_zipkin_ZipkinTracerBuilder.adoc[ZipkinTracerBuilder (tracing.providers.zipkin)] -- xref:{rootdir}/config/io_opentracing_Tracer.adoc[io_opentracing_Tracer] -- xref:{rootdir}/config/org_eclipse_microprofile_config_Config.adoc[org_eclipse_microprofile_config_Config] diff --git a/docs/src/main/asciidoc/config/io_helidon_common_configurable_AllowList.adoc b/docs/src/main/asciidoc/config/io_helidon_common_configurable_AllowList.adoc deleted file mode 100644 index 44d46254466..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_common_configurable_AllowList.adoc +++ /dev/null @@ -1,77 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.common.configurable.AllowList -:keywords: helidon, config, io.helidon.common.configurable.AllowList -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.common.configurable.AllowList -include::{rootdir}/includes/attributes.adoc[] - -= AllowList (common.configurable) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.common.configurable/io/helidon/common/configurable/AllowList.html[io.helidon.common.configurable.AllowList] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`allow.all` |boolean |`false` |Allows all strings to match (subject to "deny" conditions). An `allow.all` setting of `false` does -not deny all strings but rather represents the absence of a universal match, meaning that other allow and deny settings -determine the matching outcomes. - -Whether to allow all strings to match (subject to "deny" conditions) -|`allow.exact` |string[] |{nbsp} |Exact strings to allow. - -Exact strings to allow -|`allow.pattern` |Pattern[] |{nbsp} |Patterns specifying strings to allow. - -Patterns which allow matching -|`allow.prefix` |string[] |{nbsp} |Prefixes specifying strings to allow. - -Prefixes which allow matching -|`allow.suffix` |string[] |{nbsp} |Suffixes specifying strings to allow. - -Suffixes which allow matching -|`deny.exact` |string[] |{nbsp} |Exact strings to deny. - -Exact strings to deny -|`deny.pattern` |Pattern[] |{nbsp} |Patterns specifying strings to deny. - -Patterns which deny matching -|`deny.prefix` |string[] |{nbsp} |Prefixes specifying strings to deny. - -Prefixes which deny matching -|`deny.suffix` |string[] |{nbsp} |Suffixes specifying strings to deny. - -Suffixes which deny matching - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_common_configurable_LruCache.adoc b/docs/src/main/asciidoc/config/io_helidon_common_configurable_LruCache.adoc deleted file mode 100644 index b840fef899d..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_common_configurable_LruCache.adoc +++ /dev/null @@ -1,51 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.common.configurable.LruCache -:keywords: helidon, config, io.helidon.common.configurable.LruCache -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.common.configurable.LruCache -include::{rootdir}/includes/attributes.adoc[] - -= LruCache (common.configurable) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.common.configurable/io/helidon/common/configurable/LruCache.html[io.helidon.common.configurable.LruCache] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`capacity` |int |`10000` |Configure capacity of the cache. Defaults to LruCache.DEFAULT_CAPACITY. - -Maximal number of records in the cache before the oldest one is removed - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_common_configurable_Resource.adoc b/docs/src/main/asciidoc/config/io_helidon_common_configurable_Resource.adoc deleted file mode 100644 index 971519477d9..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_common_configurable_Resource.adoc +++ /dev/null @@ -1,78 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.common.configurable.Resource -:keywords: helidon, config, io.helidon.common.configurable.Resource -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.common.configurable.Resource -include::{rootdir}/includes/attributes.adoc[] - -= Resource (common.configurable) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.common.configurable/io/helidon/common/configurable/Resource.html[io.helidon.common.configurable.Resource] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`content` |string |{nbsp} |Binary content of the resource (base64 encoded). - -Binary content -|`content-plain` |string |{nbsp} |Plain content of the resource (text). - -Plain content -|`description` |string |{nbsp} |Description of this resource when configured through plain text or binary. - -Description -|`path` |Path |{nbsp} |Resource is located on filesystem. - -Path of the resource -|`proxy-host` |string |{nbsp} |Host of the proxy when using URI. - -Proxy host -|`proxy-port` |int |`80` |Port of the proxy when using URI. - -Proxy port -|`resource-path` |string |{nbsp} |Resource is located on classpath. - -Classpath location of the resource -|`uri` |URI |{nbsp} |Resource is available on a java.net.URI. - -Of the resource -See proxy() -See useProxy() -|`use-proxy` |boolean |`true` |Whether to use proxy. If set to `false`, proxy will not be used even if configured. -When set to `true` (default), proxy will be used if configured. - -Whether to use proxy if configured - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_common_configurable_ScheduledThreadPoolConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_common_configurable_ScheduledThreadPoolConfig.adoc deleted file mode 100644 index 4343535007a..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_common_configurable_ScheduledThreadPoolConfig.adoc +++ /dev/null @@ -1,69 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.common.configurable.ScheduledThreadPoolSupplier -:keywords: helidon, config, io.helidon.common.configurable.ScheduledThreadPoolSupplier -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.common.configurable.ScheduledThreadPoolSupplier -include::{rootdir}/includes/attributes.adoc[] - -= ScheduledThreadPoolSupplier (common.configurable) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.common.configurable/io/helidon/common/configurable/ScheduledThreadPoolSupplier.html[io.helidon.common.configurable.ScheduledThreadPoolSupplier] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`core-pool-size` |int |`16` |Core pool size of the thread pool executor. -Defaults to DEFAULT_CORE_POOL_SIZE. - -CorePoolSize see java.util.concurrent.ThreadPoolExecutor.getCorePoolSize() -|`is-daemon` |boolean |`true` |Is daemon of the thread pool executor. -Defaults to DEFAULT_IS_DAEMON. - -Whether the threads are daemon threads -|`prestart` |boolean |`false` |Whether to prestart core threads in this thread pool executor. -Defaults to DEFAULT_PRESTART. - -Whether to prestart the threads -|`thread-name-prefix` |string |`helidon-` |Name prefix for threads in this thread pool executor. -Defaults to DEFAULT_THREAD_NAME_PREFIX. - -Prefix of a thread name -|`virtual-threads` |boolean |{nbsp} |When configured to `true`, an unbounded virtual executor service (project Loom) will be used. - -If enabled, all other configuration options of this executor service are ignored! - -Whether to use virtual threads or not, defaults to `false` - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_common_configurable_ScheduledThreadPoolSupplier.adoc b/docs/src/main/asciidoc/config/io_helidon_common_configurable_ScheduledThreadPoolSupplier.adoc deleted file mode 100644 index 4343535007a..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_common_configurable_ScheduledThreadPoolSupplier.adoc +++ /dev/null @@ -1,69 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.common.configurable.ScheduledThreadPoolSupplier -:keywords: helidon, config, io.helidon.common.configurable.ScheduledThreadPoolSupplier -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.common.configurable.ScheduledThreadPoolSupplier -include::{rootdir}/includes/attributes.adoc[] - -= ScheduledThreadPoolSupplier (common.configurable) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.common.configurable/io/helidon/common/configurable/ScheduledThreadPoolSupplier.html[io.helidon.common.configurable.ScheduledThreadPoolSupplier] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`core-pool-size` |int |`16` |Core pool size of the thread pool executor. -Defaults to DEFAULT_CORE_POOL_SIZE. - -CorePoolSize see java.util.concurrent.ThreadPoolExecutor.getCorePoolSize() -|`is-daemon` |boolean |`true` |Is daemon of the thread pool executor. -Defaults to DEFAULT_IS_DAEMON. - -Whether the threads are daemon threads -|`prestart` |boolean |`false` |Whether to prestart core threads in this thread pool executor. -Defaults to DEFAULT_PRESTART. - -Whether to prestart the threads -|`thread-name-prefix` |string |`helidon-` |Name prefix for threads in this thread pool executor. -Defaults to DEFAULT_THREAD_NAME_PREFIX. - -Prefix of a thread name -|`virtual-threads` |boolean |{nbsp} |When configured to `true`, an unbounded virtual executor service (project Loom) will be used. - -If enabled, all other configuration options of this executor service are ignored! - -Whether to use virtual threads or not, defaults to `false` - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_common_configurable_ThreadPoolConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_common_configurable_ThreadPoolConfig.adoc deleted file mode 100644 index 27843db096e..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_common_configurable_ThreadPoolConfig.adoc +++ /dev/null @@ -1,101 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.common.configurable.ThreadPoolSupplier -:keywords: helidon, config, io.helidon.common.configurable.ThreadPoolSupplier -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.common.configurable.ThreadPoolSupplier -include::{rootdir}/includes/attributes.adoc[] - -= ThreadPoolSupplier (common.configurable) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.common.configurable/io/helidon/common/configurable/ThreadPoolSupplier.html[io.helidon.common.configurable.ThreadPoolSupplier] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`core-pool-size` |int |`10` |Core pool size of the thread pool executor. -Defaults to DEFAULT_CORE_POOL_SIZE. - -CorePoolSize see java.util.concurrent.ThreadPoolExecutor.getCorePoolSize() -|`growth-rate` |int |`0` |The percentage of task submissions that should result in adding threads, expressed as a value from 1 to 100. The -rate applies only when all of the following are true: - -- the pool size is below the maximum, and -- there are no idle threads, and -- the number of tasks in the queue exceeds the `growthThreshold` - -For example, a rate of 20 means that while these conditions are met one thread will be added for every 5 submitted -tasks. - -Defaults to DEFAULT_GROWTH_RATE - -The growth rate -|`growth-threshold` |int |`1000` |The queue size above which pool growth will be considered if the pool is not fixed size. -Defaults to DEFAULT_GROWTH_THRESHOLD. - -The growth threshold -|`is-daemon` |boolean |`true` |Is daemon of the thread pool executor. -Defaults to DEFAULT_IS_DAEMON. - -Whether the threads are daemon threads -|`keep-alive` |Duration |`PT3M` |Keep alive of the thread pool executor. -Defaults to DEFAULT_KEEP_ALIVE. - -Keep alive see java.util.concurrent.ThreadPoolExecutor.getKeepAliveTime(java.util.concurrent.TimeUnit) -|`max-pool-size` |int |`50` |Max pool size of the thread pool executor. -Defaults to DEFAULT_MAX_POOL_SIZE. - -MaxPoolSize see java.util.concurrent.ThreadPoolExecutor.getMaximumPoolSize() -|`name` |string |{nbsp} |Name of this thread pool executor. - -The pool name -|`queue-capacity` |int |`10000` |Queue capacity of the thread pool executor. -Defaults to DEFAULT_QUEUE_CAPACITY. - -Capacity of the queue backing the executor -|`should-prestart` |boolean |`true` |Whether to prestart core threads in this thread pool executor. -Defaults to DEFAULT_PRESTART. - -Whether to prestart the threads -|`thread-name-prefix` |string |{nbsp} |Name prefix for threads in this thread pool executor. -Defaults to DEFAULT_THREAD_NAME_PREFIX. - -Prefix of a thread name -|`virtual-threads` |boolean |{nbsp} |When configured to `true`, an unbounded virtual executor service (project Loom) will be used. - -If enabled, all other configuration options of this executor service are ignored! - -Whether to use virtual threads or not, defaults to `false` - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_common_configurable_ThreadPoolSupplier.adoc b/docs/src/main/asciidoc/config/io_helidon_common_configurable_ThreadPoolSupplier.adoc deleted file mode 100644 index 27843db096e..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_common_configurable_ThreadPoolSupplier.adoc +++ /dev/null @@ -1,101 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.common.configurable.ThreadPoolSupplier -:keywords: helidon, config, io.helidon.common.configurable.ThreadPoolSupplier -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.common.configurable.ThreadPoolSupplier -include::{rootdir}/includes/attributes.adoc[] - -= ThreadPoolSupplier (common.configurable) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.common.configurable/io/helidon/common/configurable/ThreadPoolSupplier.html[io.helidon.common.configurable.ThreadPoolSupplier] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`core-pool-size` |int |`10` |Core pool size of the thread pool executor. -Defaults to DEFAULT_CORE_POOL_SIZE. - -CorePoolSize see java.util.concurrent.ThreadPoolExecutor.getCorePoolSize() -|`growth-rate` |int |`0` |The percentage of task submissions that should result in adding threads, expressed as a value from 1 to 100. The -rate applies only when all of the following are true: - -- the pool size is below the maximum, and -- there are no idle threads, and -- the number of tasks in the queue exceeds the `growthThreshold` - -For example, a rate of 20 means that while these conditions are met one thread will be added for every 5 submitted -tasks. - -Defaults to DEFAULT_GROWTH_RATE - -The growth rate -|`growth-threshold` |int |`1000` |The queue size above which pool growth will be considered if the pool is not fixed size. -Defaults to DEFAULT_GROWTH_THRESHOLD. - -The growth threshold -|`is-daemon` |boolean |`true` |Is daemon of the thread pool executor. -Defaults to DEFAULT_IS_DAEMON. - -Whether the threads are daemon threads -|`keep-alive` |Duration |`PT3M` |Keep alive of the thread pool executor. -Defaults to DEFAULT_KEEP_ALIVE. - -Keep alive see java.util.concurrent.ThreadPoolExecutor.getKeepAliveTime(java.util.concurrent.TimeUnit) -|`max-pool-size` |int |`50` |Max pool size of the thread pool executor. -Defaults to DEFAULT_MAX_POOL_SIZE. - -MaxPoolSize see java.util.concurrent.ThreadPoolExecutor.getMaximumPoolSize() -|`name` |string |{nbsp} |Name of this thread pool executor. - -The pool name -|`queue-capacity` |int |`10000` |Queue capacity of the thread pool executor. -Defaults to DEFAULT_QUEUE_CAPACITY. - -Capacity of the queue backing the executor -|`should-prestart` |boolean |`true` |Whether to prestart core threads in this thread pool executor. -Defaults to DEFAULT_PRESTART. - -Whether to prestart the threads -|`thread-name-prefix` |string |{nbsp} |Name prefix for threads in this thread pool executor. -Defaults to DEFAULT_THREAD_NAME_PREFIX. - -Prefix of a thread name -|`virtual-threads` |boolean |{nbsp} |When configured to `true`, an unbounded virtual executor service (project Loom) will be used. - -If enabled, all other configuration options of this executor service are ignored! - -Whether to use virtual threads or not, defaults to `false` - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_common_pki_Keys.adoc b/docs/src/main/asciidoc/config/io_helidon_common_pki_Keys.adoc deleted file mode 100644 index 0fa04a3f930..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_common_pki_Keys.adoc +++ /dev/null @@ -1,58 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.common.pki.Keys -:keywords: helidon, config, io.helidon.common.pki.Keys -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.common.pki.Keys -include::{rootdir}/includes/attributes.adoc[] - -= Keys (common.pki) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.common.pki/io/helidon/common/pki/Keys.html[io.helidon.common.pki.Keys] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`keystore` |xref:{rootdir}/config/io_helidon_common_pki_KeystoreKeys.adoc[KeystoreKeys] |{nbsp} |Configure keys from a keystore. -Once the config object is built, this option will ALWAYS be empty. All keys from the keystore will be -populated to privateKey(), publicKey(), publicCert() etc. - -Keystore configuration -|`pem` |xref:{rootdir}/config/io_helidon_common_pki_PemKeys.adoc[PemKeys] |{nbsp} |Configure keys from pem file(s). -Once the config object is built, this option will ALWAYS be empty. All keys from the keystore will be -populated to privateKey(), publicKey(), publicCert() etc. - -Pem based definition - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_common_pki_KeystoreKeys.adoc b/docs/src/main/asciidoc/config/io_helidon_common_pki_KeystoreKeys.adoc deleted file mode 100644 index ef3721069cd..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_common_pki_KeystoreKeys.adoc +++ /dev/null @@ -1,86 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.common.pki.KeystoreKeys -:keywords: helidon, config, io.helidon.common.pki.KeystoreKeys -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.common.pki.KeystoreKeys -include::{rootdir}/includes/attributes.adoc[] - -= KeystoreKeys (common.pki) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.common.pki/io/helidon/common/pki/KeystoreKeys.html[io.helidon.common.pki.KeystoreKeys] - - - - -== Configuration options - -.Required configuration options -[cols="3,3a,2,5a"] -|=== -|key |type |default value |description - -|`resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Keystore resource definition. - -Keystore resource, from file path, classpath, URL etc. - -|=== - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`cert-chain.alias` |string |{nbsp} |Alias of an X.509 chain. - -Alias of certificate chain in the keystore -|`cert.alias` |string |{nbsp} |Alias of X.509 certificate of public key. -Used to load both the certificate and public key. - -Alias under which the certificate is stored in the keystore -|`key.alias` |string |{nbsp} |Alias of the private key in the keystore. - -Alias of the key in the keystore -|`key.passphrase` |char[] |{nbsp} |Pass-phrase of the key in the keystore (used for private keys). -This is (by default) the same as keystore passphrase - only configure -if it differs from keystore passphrase. - -Pass-phrase of the key -|`passphrase` |char[] |{nbsp} |Pass-phrase of the keystore (supported with JKS and PKCS12 keystores). - -Keystore password to use -|`trust-store` |boolean |`false` |If you want to build a trust store, call this method to add all -certificates present in the keystore to certificate list. - -Whether this is a trust store -|`type` |string |`PKCS12` |Set type of keystore. -Defaults to DEFAULT_KEYSTORE_TYPE, -expected are other keystore types supported by java then can store keys under aliases. - -Keystore type to load the key - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_common_pki_PemKeys.adoc b/docs/src/main/asciidoc/config/io_helidon_common_pki_PemKeys.adoc deleted file mode 100644 index 86165efb690..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_common_pki_PemKeys.adoc +++ /dev/null @@ -1,64 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.common.pki.PemKeys -:keywords: helidon, config, io.helidon.common.pki.PemKeys -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.common.pki.PemKeys -include::{rootdir}/includes/attributes.adoc[] - -= PemKeys (common.pki) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.common.pki/io/helidon/common/pki/PemKeys.html[io.helidon.common.pki.PemKeys] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`cert-chain.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Load certificate chain from PEM resource. - -Resource (e.g. classpath, file path, URL etc.) -|`certificates.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Read one or more certificates in PEM format from a resource definition. Used eg: in a trust store. - -Key resource (file, classpath, URL etc.) -|`key.passphrase` |char[] |{nbsp} |Passphrase for private key. If the key is encrypted (and in PEM PKCS#8 format), this passphrase will be used to -decrypt it. - -Passphrase used to encrypt the private key -|`key.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Read a private key from PEM format from a resource definition. - -Key resource (file, classpath, URL etc.) -|`public-key.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Read a public key from PEM format from a resource definition. - -Public key resource (file, classpath, URL etc.) - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_common_socket_SocketOptions.adoc b/docs/src/main/asciidoc/config/io_helidon_common_socket_SocketOptions.adoc deleted file mode 100644 index c3b74f7d34d..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_common_socket_SocketOptions.adoc +++ /dev/null @@ -1,77 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.common.socket.SocketOptions -:keywords: helidon, config, io.helidon.common.socket.SocketOptions -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.common.socket.SocketOptions -include::{rootdir}/includes/attributes.adoc[] - -= SocketOptions (common.socket) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.common.socket/io/helidon/common/socket/SocketOptions.html[io.helidon.common.socket.SocketOptions] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`connect-timeout` |Duration |`PT10S` |Socket connect timeout. Default is 10 seconds. - -Connect timeout duration -|`read-timeout` |Duration |`PT30S` |Socket read timeout. Default is 30 seconds. - -Read timeout duration -|`socket-keep-alive` |boolean |`true` |Configure socket keep alive. -Default is `true`. - -Keep alive -See java.net.StandardSocketOptions.SO_KEEPALIVE -|`socket-receive-buffer-size` |int |{nbsp} |Socket receive buffer size. - -Buffer size, in bytes -See java.net.StandardSocketOptions.SO_RCVBUF -|`socket-reuse-address` |boolean |`true` |Socket reuse address. -Default is `true`. - -Whether to reuse address -See java.net.StandardSocketOptions.SO_REUSEADDR -|`socket-send-buffer-size` |int |{nbsp} |Socket send buffer size. - -Buffer size, in bytes -See java.net.StandardSocketOptions.SO_SNDBUF -|`tcp-no-delay` |boolean |`false` |This option may improve performance on some systems. -Default is `false`. - -Whether to use TCP_NODELAY, defaults to `false` -See java.net.StandardSocketOptions.TCP_NODELAY - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_common_tls_RevocationConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_common_tls_RevocationConfig.adoc deleted file mode 100644 index 3dd53382018..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_common_tls_RevocationConfig.adoc +++ /dev/null @@ -1,83 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.common.tls.RevocationConfig -:keywords: helidon, config, io.helidon.common.tls.RevocationConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.common.tls.RevocationConfig -include::{rootdir}/includes/attributes.adoc[] - -= RevocationConfig (common.tls) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.common.tls/io/helidon/common/tls/RevocationConfig.html[io.helidon.common.tls.RevocationConfig] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`check-only-end-entity` |boolean |`false` |Only check the revocation status of end-entity certificates. -Default value is `false`. - -Whether to check only end-entity certificates -|`enabled` |boolean |`false` |Flag indicating whether this revocation config is enabled. - -Enabled flag -|`fallback-enabled` |boolean |`true` |Enable fallback to the less preferred checking option. - -If the primary method for revocation checking fails to verify the revocation status of a certificate -(such as using a CRL or OCSP), the checker will attempt alternative methods. This option ensures -whether revocation checking is performed strictly according to the specified method, or should fallback -to the one less preferred. OCSP is preferred over the CRL by default. - -Whether to allow fallback to the less preferred checking option -|`ocsp-responder-uri` |URI |{nbsp} |The URI that identifies the location of the OCSP responder. This -overrides the `ocsp.responderURL` security property and any -responder specified in a certificate's Authority Information Access -Extension, as defined in RFC 5280. - -OCSP responder URI -|`prefer-crl-over-ocsp` |boolean |`false` |Prefer CRL over OCSP. -Default value is `false`. OCSP is preferred over the CRL by default. - -Whether to prefer CRL over OCSP -|`soft-fail-enabled` |boolean |`false` |Allow revocation check to succeed if the revocation status cannot be -determined for one of the following reasons: - -- The CRL or OCSP response cannot be obtained because of a - network error. - -- The OCSP responder returns one of the following errors - specified in section 2.3 of RFC 2560: internalError or tryLater. - -Whether soft fail is enabled - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_common_tls_Tls.adoc b/docs/src/main/asciidoc/config/io_helidon_common_tls_Tls.adoc deleted file mode 100644 index cd75173fc43..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_common_tls_Tls.adoc +++ /dev/null @@ -1,132 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.common.tls.Tls -:keywords: helidon, config, io.helidon.common.tls.Tls -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.common.tls.Tls -include::{rootdir}/includes/attributes.adoc[] - -= Tls (common.tls) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.common.tls/io/helidon/common/tls/Tls.html[io.helidon.common.tls.Tls] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`cipher-suite` |string[] |{nbsp} |Enabled cipher suites for TLS communication. - -Cipher suites to enable, by default (or if list is empty), all available cipher suites - are enabled -|`client-auth` |TlsClientAuth (REQUIRED, OPTIONAL, NONE) |`TlsClientAuth.NONE` |Configure requirement for mutual TLS. - -What type of mutual TLS to use, defaults to TlsClientAuth.NONE - -Allowed values: - -- `REQUIRED`: Mutual TLS is required. -Server MUST present a certificate trusted by the client, client MUST present a certificate trusted by the server. -This implies private key and trust configuration for both server and client. -- `OPTIONAL`: Mutual TLS is optional. -Server MUST present a certificate trusted by the client, client MAY present a certificate trusted by the server. -This implies private key configuration at least for server, trust configuration for at least client. -- `NONE`: Mutual TLS is disabled. -Server MUST present a certificate trusted by the client, client does not present a certificate. -This implies private key configuration for server, trust configuration for client. - -|`enabled` |boolean |`true` |Flag indicating whether Tls is enabled. - -Enabled flag -|`endpoint-identification-algorithm` |string |`HTTPS` |Identification algorithm for SSL endpoints. - -Configure endpoint identification algorithm, or set to `NONE` - to disable endpoint identification (equivalent to hostname verification). - Defaults to Tls.ENDPOINT_IDENTIFICATION_HTTPS -|`internal-keystore-provider` |string |{nbsp} |Provider of the key stores used internally to create a key and trust manager factories. - -Keystore provider, if not defined, provider is not specified -|`internal-keystore-type` |string |{nbsp} |Type of the key stores used internally to create a key and trust manager factories. - -Keystore type, defaults to java.security.KeyStore.getDefaultType() -|`key-manager-factory-algorithm` |string |{nbsp} |Algorithm of the key manager factory used when private key is defined. -Defaults to javax.net.ssl.KeyManagerFactory.getDefaultAlgorithm(). - -Algorithm to use -|`manager` |io.helidon.common.tls.TlsManager (service provider interface) |{nbsp} |The Tls manager. If one is not explicitly defined in the config then a default manager will be created. - -The tls manager of the tls instance -See ConfiguredTlsManager -|`private-key` |PrivateKey |{nbsp} |Private key to use. For server side TLS, this is required. -For client side TLS, this is optional (used when mutual TLS is enabled). - -Private key to use -|`protocol` |string |`TLS` |Configure the protocol used to obtain an instance of javax.net.ssl.SSLContext. - -Protocol to use, defaults to DEFAULT_PROTOCOL -|`protocols` |string[] |{nbsp} |Enabled protocols for TLS communication. -Example of valid values for `TLS` protocol: `TLSv1.3`, `TLSv1.2` - -Protocols to enable, by default (or if list is empty), all available protocols are enabled -|`provider` |string |{nbsp} |Use explicit provider to obtain an instance of javax.net.ssl.SSLContext. - -Provider to use, defaults to none (only protocol() is used by default) -|`revocation` |xref:{rootdir}/config/io_helidon_common_tls_RevocationConfig.adoc[RevocationConfig] |{nbsp} |Certificate revocation check configuration. - -Certificate revocation configuration -|`secure-random-algorithm` |string |{nbsp} |Algorithm to use when creating a new secure random. - -Algorithm to use, by default uses java.security.SecureRandom constructor -|`secure-random-provider` |string |{nbsp} |Provider to use when creating a new secure random. -When defined, secureRandomAlgorithm() must be defined as well. - -Provider to use, by default no provider is specified -|`session-cache-size` |int |`20480` |SSL session cache size. - -Session cache size, defaults to DEFAULT_SESSION_CACHE_SIZE. -|`session-timeout` |Duration |`PT24H` |SSL session timeout. - -Session timeout, defaults to DEFAULT_SESSION_TIMEOUT. -|`trust` |X509Certificate[] |{nbsp} |List of certificates that form the trust manager. - -Certificates to be trusted -|`trust-all` |boolean |`false` |Trust any certificate provided by the other side of communication. - -*This is a dangerous setting:* if set to `true`, any certificate will be accepted, throwing away -most of the security advantages of TLS. *NEVER* do this in production. - -Whether to trust all certificates, do not use in production -|`trust-manager-factory-algorithm` |string |{nbsp} |Trust manager factory algorithm. - -Algorithm to use - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_config_mp_MpConfigBuilder.adoc b/docs/src/main/asciidoc/config/io_helidon_config_mp_MpConfigBuilder.adoc deleted file mode 100644 index 15222991777..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_config_mp_MpConfigBuilder.adoc +++ /dev/null @@ -1,51 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of org.eclipse.microprofile.config.Config -:keywords: helidon, config, org.eclipse.microprofile.config.Config -:basic-table-intro: The table below lists the configuration keys that configure org.eclipse.microprofile.config.Config -include::{rootdir}/includes/attributes.adoc[] - -= org.eclipse.microprofile.config.Config Configuration - -// tag::config[] - - -Type: org.eclipse.microprofile.config.Config - - -This is a standalone configuration type, prefix from configuration root: `mp.config` - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`profile` |string |{nbsp} |Configure an explicit profile name. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_cors_CrossOriginConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_cors_CrossOriginConfig.adoc deleted file mode 100644 index ff750f91b51..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_cors_CrossOriginConfig.adoc +++ /dev/null @@ -1,56 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.cors.CrossOriginConfig -:keywords: helidon, config, io.helidon.cors.CrossOriginConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.cors.CrossOriginConfig -include::{rootdir}/includes/attributes.adoc[] - -= CrossOriginConfig (cors) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.cors/io/helidon/cors/CrossOriginConfig.html[io.helidon.cors.CrossOriginConfig] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`allow-credentials` |boolean |`false` |Sets the allow credentials flag. -|`allow-headers` |string[] |`*` |Sets the allow headers. -|`allow-methods` |string[] |`*` |Sets the allow methods. -|`allow-origins` |string[] |`*` |Sets the allowOrigins. -|`enabled` |boolean |`true` |Sets whether this config should be enabled or not. -|`expose-headers` |string[] |{nbsp} |Sets the expose headers. -|`max-age-seconds` |long |`3600` |Sets the maximum age. -|`path-pattern` |string |`{+}` |Updates the path prefix for this cross-origin config. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_dbclient_jdbc_JdbcParametersConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_dbclient_jdbc_JdbcParametersConfig.adoc deleted file mode 100644 index db6fe8a629c..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_dbclient_jdbc_JdbcParametersConfig.adoc +++ /dev/null @@ -1,90 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.dbclient.jdbc.JdbcParametersConfig -:keywords: helidon, config, io.helidon.dbclient.jdbc.JdbcParametersConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.dbclient.jdbc.JdbcParametersConfig -include::{rootdir}/includes/attributes.adoc[] - -= JdbcParametersConfig (dbclient.jdbc) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.dbclient.jdbc/io/helidon/dbclient/jdbc/JdbcParametersConfig.html[io.helidon.dbclient.jdbc.JdbcParametersConfig] - - -[source,text] -.Config key ----- -parameters ----- - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`set-object-for-java-time` |boolean |`true` |Set all `java.time` Date/Time values directly using java.sql.PreparedStatement.setObject(int, Object). -This option shall work fine for recent JDBC drivers. -Default value is `true`. - -Whether to use java.sql.PreparedStatement.setObject(int, Object) for `java.time` Date/Time values -|`string-binding-size` |int |`1024` |String values with length above this limit will be bound -using java.sql.PreparedStatement.setCharacterStream(int, java.io.Reader, int) -if useStringBinding() is set to `true`. -Default value is `1024`. - -String values length limit for java.io.CharArrayReader binding -|`timestamp-for-local-time` |boolean |`true` |Use java.sql.PreparedStatement.setTimestamp(int, java.sql.Timestamp) -to set java.time.LocalTime values when `true` -or use java.sql.PreparedStatement.setTime(int, java.sql.Time) when `false`. -Default value is `true`. -This option is vendor specific. Most of the databases are fine with java.sql.Timestamp, -but for example SQL Server requires java.sql.Time. -This option does not apply when setObjectForJavaTime() is set to `true`. - -Whether to use java.sql.Timestamp instead of java.sql.Time - for java.time.LocalTime values -|`use-byte-array-binding` |boolean |`true` |Use java.sql.PreparedStatement.setBinaryStream(int, java.io.InputStream, int) binding -for `byte[]` values. -Default value is `true`. - -Whether to use java.io.ByteArrayInputStream binding -|`use-n-string` |boolean |`false` |Use SQL `NCHAR`, `NVARCHAR` or `LONGNVARCHAR` value conversion -for String values. -Default value is `false`. - -Whether NString conversion is used -|`use-string-binding` |boolean |`true` |Use java.sql.PreparedStatement.setCharacterStream(int, java.io.Reader, int) binding -for String values with length above stringBindingSize() limit. -Default value is `true`. - -Whether to use java.io.CharArrayReader binding - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Async.adoc b/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Async.adoc deleted file mode 100644 index 13d24ed588e..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Async.adoc +++ /dev/null @@ -1,52 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.faulttolerance.Async -:keywords: helidon, config, io.helidon.faulttolerance.Async -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.faulttolerance.Async -include::{rootdir}/includes/attributes.adoc[] - -= Async (faulttolerance) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.faulttolerance/io/helidon/faulttolerance/Async.html[io.helidon.faulttolerance.Async] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`executor-name` |string |{nbsp} |Name of an executor service. This is only honored when service registry is used. - -Name fo the java.util.concurrent.ExecutorService to lookup -See executor() - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Bulkhead.adoc b/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Bulkhead.adoc deleted file mode 100644 index 8a7645c5e00..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Bulkhead.adoc +++ /dev/null @@ -1,59 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.faulttolerance.Bulkhead -:keywords: helidon, config, io.helidon.faulttolerance.Bulkhead -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.faulttolerance.Bulkhead -include::{rootdir}/includes/attributes.adoc[] - -= Bulkhead (faulttolerance) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.faulttolerance/io/helidon/faulttolerance/Bulkhead.html[io.helidon.faulttolerance.Bulkhead] - - -This is a standalone configuration type, prefix from configuration root: `fault-tolerance.bulkheads` - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`limit` |int |`10` |Maximal number of parallel requests going through this bulkhead. -When the limit is reached, additional requests are enqueued. - -Maximal number of parallel calls, defaults is DEFAULT_LIMIT -|`queue-length` |int |`10` |Maximal number of enqueued requests waiting for processing. -When the limit is reached, additional attempts to invoke -a request will receive a BulkheadException. - -Length of the queue - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_faulttolerance_CircuitBreaker.adoc b/docs/src/main/asciidoc/config/io_helidon_faulttolerance_CircuitBreaker.adoc deleted file mode 100644 index ea06b3b349c..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_faulttolerance_CircuitBreaker.adoc +++ /dev/null @@ -1,70 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.faulttolerance.CircuitBreaker -:keywords: helidon, config, io.helidon.faulttolerance.CircuitBreaker -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.faulttolerance.CircuitBreaker -include::{rootdir}/includes/attributes.adoc[] - -= CircuitBreaker (faulttolerance) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.faulttolerance/io/helidon/faulttolerance/CircuitBreaker.html[io.helidon.faulttolerance.CircuitBreaker] - - -This is a standalone configuration type, prefix from configuration root: `fault-tolerance.circuit-breakers` - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`delay` |Duration |`PT5S` |How long to wait before transitioning from open to half-open state. - -Delay -|`error-ratio` |int |`60` |How many failures out of 100 will trigger the circuit to open. -This is adapted to the volume() used to handle the window of requests. -If errorRatio is 40, and volume is 10, 4 failed requests will open the circuit. -Default is DEFAULT_ERROR_RATIO. - -Percent of failure that trigger the circuit to open -See volume() -|`success-threshold` |int |`1` |How many successful calls will close a half-open circuit. -Nevertheless, the first failed call will open the circuit again. -Default is DEFAULT_SUCCESS_THRESHOLD. - -Number of calls -|`volume` |int |`10` |Rolling window size used to calculate ratio of failed requests. -Default is DEFAULT_VOLUME. - -How big a window is used to calculate error errorRatio -See errorRatio() - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Retry.adoc b/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Retry.adoc deleted file mode 100644 index 58e69696b83..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Retry.adoc +++ /dev/null @@ -1,71 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.faulttolerance.Retry -:keywords: helidon, config, io.helidon.faulttolerance.Retry -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.faulttolerance.Retry -include::{rootdir}/includes/attributes.adoc[] - -= Retry (faulttolerance) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.faulttolerance/io/helidon/faulttolerance/Retry.html[io.helidon.faulttolerance.Retry] - - -This is a standalone configuration type, prefix from configuration root: `fault-tolerance.retries` - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`calls` |int |`3` |Number of calls (first try + retries). - -Number of desired calls, must be 1 (means no retries) or higher. -|`delay` |Duration |`PT0.2S` |Base delay between try and retry. -Defaults to `200 ms`. - -Delay between retries (combines with retry policy) -|`delay-factor` |double |`-1.0` |Delay retry policy factor. If unspecified (value of `-1`), Jitter retry policy would be used, unless -jitter is also unspecified. - -Default when Retry.DelayingRetryPolicy is used is `2`. - -Delay factor for delaying retry policy -|`jitter` |Duration |`PT-1S` |Jitter for Retry.JitterRetryPolicy. If unspecified (value of `-1`), -delaying retry policy is used. If both this value, and delayFactor() are specified, delaying retry policy -would be used. - -Jitter -|`overall-timeout` |Duration |`PT1S` |Overall timeout of all retries combined. - -Overall timeout - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Timeout.adoc b/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Timeout.adoc deleted file mode 100644 index d8a0ad4beeb..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_faulttolerance_Timeout.adoc +++ /dev/null @@ -1,58 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.faulttolerance.Timeout -:keywords: helidon, config, io.helidon.faulttolerance.Timeout -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.faulttolerance.Timeout -include::{rootdir}/includes/attributes.adoc[] - -= Timeout (faulttolerance) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.faulttolerance/io/helidon/faulttolerance/Timeout.html[io.helidon.faulttolerance.Timeout] - - -This is a standalone configuration type, prefix from configuration root: `fault-tolerance.timeouts` - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`current-thread` |boolean |`false` |Flag to indicate that code must be executed in current thread instead -of in an executor's thread. This flag is `false` by default. - -Whether to execute on current thread (`true`), or in an executor service (`false`}) -|`timeout` |Duration |`PT10S` |Duration to wait before timing out. -Defaults to `10 seconds`. - -Timeout - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_http_RequestedUriDiscoveryContext.adoc b/docs/src/main/asciidoc/config/io_helidon_http_RequestedUriDiscoveryContext.adoc deleted file mode 100644 index d1f5a96f870..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_http_RequestedUriDiscoveryContext.adoc +++ /dev/null @@ -1,64 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.http.RequestedUriDiscoveryContext -:keywords: helidon, config, io.helidon.http.RequestedUriDiscoveryContext -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.http.RequestedUriDiscoveryContext -include::{rootdir}/includes/attributes.adoc[] - -= RequestedUriDiscoveryContext (http) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.http/io/helidon/http/RequestedUriDiscoveryContext.html[io.helidon.http.RequestedUriDiscoveryContext] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`enabled` |boolean |`true if 'types' or 'trusted-proxies' is set; false otherwise` |Sets whether requested URI discovery is enabled for requestes arriving on the socket. -|`trusted-proxies` |xref:{rootdir}/config/io_helidon_common_configurable_AllowList.adoc[AllowList] |{nbsp} |Sets the trusted proxies for requested URI discovery for requests arriving on the socket. -|`types` |RequestedUriDiscoveryType[] (FORWARDED, X_FORWARDED, HOST) |{nbsp} |Sets the discovery types for requested URI discovery for requests arriving on the socket. - -Allowed values: - -- `FORWARDED`: The `io.helidon.http.Header#FORWARDED` header is used to discover the original requested URI. -- `X_FORWARDED`: The -`io.helidon.http.Header#X_FORWARDED_PROTO`, -`io.helidon.http.Header#X_FORWARDED_HOST`, -`io.helidon.http.Header#X_FORWARDED_PORT`, -`io.helidon.http.Header#X_FORWARDED_PREFIX` -headers are used to discover the original requested URI. -- `HOST`: This is the default, only the `io.helidon.http.Header#HOST` header is used to discover -requested URI. - - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_http_encoding_ContentEncodingContext.adoc b/docs/src/main/asciidoc/config/io_helidon_http_encoding_ContentEncodingContext.adoc deleted file mode 100644 index 88ae5154b10..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_http_encoding_ContentEncodingContext.adoc +++ /dev/null @@ -1,52 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.http.encoding.ContentEncodingContext -:keywords: helidon, config, io.helidon.http.encoding.ContentEncodingContext -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.http.encoding.ContentEncodingContext -include::{rootdir}/includes/attributes.adoc[] - -= ContentEncodingContext (http.encoding) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.http.encoding/io/helidon/http/encoding/ContentEncodingContext.html[io.helidon.http.encoding.ContentEncodingContext] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`content-encodings` |io.helidon.http.encoding.ContentEncoding[] (service provider interface) |{nbsp} |List of content encodings that should be used. -Encodings configured here have priority over encodings discovered through service loader. - -List of content encodings to be used (such as `gzip,deflate`) - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_http_media_MediaContext.adoc b/docs/src/main/asciidoc/config/io_helidon_http_media_MediaContext.adoc deleted file mode 100644 index a12f74de824..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_http_media_MediaContext.adoc +++ /dev/null @@ -1,60 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.http.media.MediaContext -:keywords: helidon, config, io.helidon.http.media.MediaContext -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.http.media.MediaContext -include::{rootdir}/includes/attributes.adoc[] - -= MediaContext (http.media) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.http.media/io/helidon/http/media/MediaContext.html[io.helidon.http.media.MediaContext] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`fallback` |xref:{rootdir}/config/io_helidon_http_media_MediaContext.adoc[MediaContext] |{nbsp} |Existing context to be used as a fallback for this context. - -Media context to use if supports configured on this request cannot provide a good result -|`media-supports` |io.helidon.http.media.MediaSupport[] (service provider interface) |{nbsp} |Media supports to use. -This instance has priority over provider(s) discovered by service loader. -The providers are used in order of calling this method, where the first support added is the -first one to be queried for readers and writers. - -Media supports -|`register-defaults` |boolean |`true` |Should we register defaults of Helidon, such as String media support. - -Whether to register default media supports - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_integrations_micrometer_MicrometerFeature.adoc b/docs/src/main/asciidoc/config/io_helidon_integrations_micrometer_MicrometerFeature.adoc deleted file mode 100644 index faf7d14e8ed..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_integrations_micrometer_MicrometerFeature.adoc +++ /dev/null @@ -1,56 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.integrations.micrometer.MicrometerFeature -:keywords: helidon, config, io.helidon.integrations.micrometer.MicrometerFeature -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.integrations.micrometer.MicrometerFeature -include::{rootdir}/includes/attributes.adoc[] - -= MicrometerFeature (integrations.micrometer) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.integrations.micrometer/io/helidon/integrations/micrometer/MicrometerFeature.html[io.helidon.integrations.micrometer.MicrometerFeature] - - -[source,text] -.Config key ----- -micrometer ----- - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`cross-origin-config` |xref:{rootdir}/config/io_helidon_cors_CrossOriginConfig.adoc[CrossOriginConfig] |{nbsp} |Set the CORS config from the specified `CrossOriginConfig` object. -|`web-context` |string |{nbsp} |Set the root context for the REST API of the service. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_integrations_neo4j_Neo4j.adoc b/docs/src/main/asciidoc/config/io_helidon_integrations_neo4j_Neo4j.adoc deleted file mode 100644 index 5f36b7c4ee1..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_integrations_neo4j_Neo4j.adoc +++ /dev/null @@ -1,69 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.integrations.neo4j.Neo4j -:keywords: helidon, config, io.helidon.integrations.neo4j.Neo4j -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.integrations.neo4j.Neo4j -include::{rootdir}/includes/attributes.adoc[] - -= Neo4j (integrations.neo4j) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.integrations.neo4j/io/helidon/integrations/neo4j/Neo4j.html[io.helidon.integrations.neo4j.Neo4j] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`authentication-enabled` |boolean |`true` |Enable authentication. -|`certificate` |Path |{nbsp} |Set certificate path. -|`connection-acquisition-timeout` |Duration |`PT1M` |Set connection acquisition timeout. -|`encrypted` |boolean |{nbsp} |Enable encrypted field. -|`hostname-verification-enabled` |boolean |{nbsp} |Enable hostname verification. -|`idle-time-before-connection-test` |Duration |`PT1MS` |Set idle time. -|`log-leaked-sessions` |boolean |{nbsp} |Enable log leaked sessions. -|`max-connection-lifetime` |Duration |`PT5H` |Set max life time. -|`max-connection-pool-size` |int |`100` |Set pool size. -|`metrics-enabled` |boolean |{nbsp} |Enable metrics. -|`password` |string |{nbsp} |Create password. -|`trust-strategy` |TrustStrategy (TRUST_ALL_CERTIFICATES, TRUST_CUSTOM_CA_SIGNED_CERTIFICATES, TRUST_SYSTEM_CA_SIGNED_CERTIFICATES) |{nbsp} |Set trust strategy. - -Allowed values: - -- `TRUST_ALL_CERTIFICATES`: Trust all. -- `TRUST_CUSTOM_CA_SIGNED_CERTIFICATES`: Trust custom certificates. -- `TRUST_SYSTEM_CA_SIGNED_CERTIFICATES`: Trust system CA. - -|`uri` |string |{nbsp} |Create uri. -|`username` |string |{nbsp} |Create username. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_ConfigFileMethodConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_integrations_oci_ConfigFileMethodConfig.adoc deleted file mode 100644 index d69eb150a69..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_ConfigFileMethodConfig.adoc +++ /dev/null @@ -1,54 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.integrations.oci.ConfigFileMethodConfig -:keywords: helidon, config, io.helidon.integrations.oci.ConfigFileMethodConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.integrations.oci.ConfigFileMethodConfig -include::{rootdir}/includes/attributes.adoc[] - -= ConfigFileMethodConfig (integrations.oci) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.integrations.oci/io/helidon/integrations/oci/ConfigFileMethodConfig.html[io.helidon.integrations.oci.ConfigFileMethodConfig] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`path` |string |{nbsp} |The OCI configuration profile path. - -The OCI configuration profile path -|`profile` |string |`DEFAULT` |The OCI configuration/auth profile name. - -The optional OCI configuration/auth profile name - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_ConfigMethodConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_integrations_oci_ConfigMethodConfig.adoc deleted file mode 100644 index 1053716e1ec..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_ConfigMethodConfig.adoc +++ /dev/null @@ -1,82 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.integrations.oci.ConfigMethodConfig -:keywords: helidon, config, io.helidon.integrations.oci.ConfigMethodConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.integrations.oci.ConfigMethodConfig -include::{rootdir}/includes/attributes.adoc[] - -= ConfigMethodConfig (integrations.oci) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.integrations.oci/io/helidon/integrations/oci/ConfigMethodConfig.html[io.helidon.integrations.oci.ConfigMethodConfig] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`fingerprint` |string |{nbsp} |The OCI authentication fingerprint. - -This configuration property must be provided in order to set the https://docs.oracle.com/en-us/iaas/Content/API/Concepts/apisigningkey.htm[API signing key's fingerprint]. -See com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getFingerprint() for more details. - -The OCI authentication fingerprint -|`passphrase` |char[] |{nbsp} |The OCI authentication passphrase. - -This property must be provided in order to set the -com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getPassphraseCharacters(). - -The OCI authentication passphrase -|`private-key` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |The OCI authentication private key resource. -A resource can be defined as a resource on classpath, file on the file system, -base64 encoded text value in config, or plain-text value in config. - -If not defined, we will use `.oci/oic_api_key.pem` file in user home directory. - -The OCI authentication key file -|`region` |string |{nbsp} |The OCI region. - -The OCI region -|`tenant-id` |string |{nbsp} |The OCI tenant id. - -This property must be provided in order to set the -com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getTenantId(). - -The OCI tenant id -|`user-id` |string |{nbsp} |The OCI user id. - -This property must be provided in order to set the -com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getUserId(). - -The OCI user id - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_ImdsInstanceInfo.adoc b/docs/src/main/asciidoc/config/io_helidon_integrations_oci_ImdsInstanceInfo.adoc deleted file mode 100644 index 5069d2b45ea..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_ImdsInstanceInfo.adoc +++ /dev/null @@ -1,75 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.integrations.oci.ImdsInstanceInfo -:keywords: helidon, config, io.helidon.integrations.oci.ImdsInstanceInfo -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.integrations.oci.ImdsInstanceInfo -include::{rootdir}/includes/attributes.adoc[] - -= ImdsInstanceInfo (integrations.oci) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.integrations.oci/io/helidon/integrations/oci/ImdsInstanceInfo.html[io.helidon.integrations.oci.ImdsInstanceInfo] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`canonical-region-name` |string |{nbsp} |Canonical Region Name. - -Canonical Region Name of where the Instance exists -|`compartment-id` |string |{nbsp} |Compartment Id. - -Compartment Id where the Instance was provisioned. -|`display-name` |string |{nbsp} |Display Name. - -Display Name of the Instance -|`fault-domain` |string |{nbsp} |Fault Domain Name. - -Fault Domain Name where the Instance exists -|`host-name` |string |{nbsp} |Host Name. - -Host Name of the Instance -|`json-object` |JsonObject |{nbsp} |Instance Data. - -Full information about the Instance as a jakarta.json.JsonObject -|`oci-ad-name` |string |{nbsp} |Oci Availability Domain Name. - -Physical Availaibility Domain Name where the Instance exists -|`region` |string |{nbsp} |Region Name. - -Short Region Name of where the Instance exists -|`tenant-id` |string |{nbsp} |Tenant Id. - -Tenant Id where the Instance was provisioned. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_OciConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_integrations_oci_OciConfig.adoc deleted file mode 100644 index 3f82d6f30f5..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_OciConfig.adoc +++ /dev/null @@ -1,110 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.integrations.oci.OciConfig -:keywords: helidon, config, io.helidon.integrations.oci.OciConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.integrations.oci.OciConfig -include::{rootdir}/includes/attributes.adoc[] - -= OciConfig (integrations.oci) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.integrations.oci/io/helidon/integrations/oci/OciConfig.html[io.helidon.integrations.oci.OciConfig] - - -This is a standalone configuration type, prefix from configuration root: `helidon.oci` - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`allowed-authentication-methods` |string[] |{nbsp} |List of attempted authentication strategies in case io.helidon.integrations.oci.OciConfig.authenticationMethod() is -set to AUTHENTICATION_METHOD_AUTO. - -In case the list is empty, all available strategies will be tried, ordered by their io.helidon.common.Weight - -List of authentication strategies to be tried -See io.helidon.integrations.oci.OciConfig.authenticationMethod() -|`authentication-method` |string |`auto` |Authentication method to use. If the configured method is not available, an exception -would be thrown for OCI related services. - -Known and supported authentication strategies for public OCI: - -- AUTHENTICATION_METHOD_AUTO - use the list of - io.helidon.integrations.oci.OciConfig.allowedAuthenticationMethods() - (in the provided order), and choose the first one capable of providing data -- AuthenticationMethodConfig.METHOD - - use configuration of the application to obtain values needed to set up connectivity, uses - com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider -- AuthenticationMethodConfigFile.METHOD - use configuration file of OCI (`home/.oci/config`), uses - com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider -- `resource-principal` - use identity of the OCI resource the service is executed on - (fn), uses - com.oracle.bmc.auth.ResourcePrincipalAuthenticationDetailsProvider, and is available in a - separate module `helidon-integrations-oci-authentication-resource` -- `instance-principal` - use identity of the OCI instance the service is running on, uses - com.oracle.bmc.auth.InstancePrincipalsAuthenticationDetailsProvider, and is available in a - separate module `helidon-integrations-oci-authentication-resource` -- `workload` - use workload identity of the OCI Kubernetes workload, available in a - separate module `helidon-integrations-oci-authentication-workload` - -The authentication method to apply -|`authentication-timeout` |Duration |`PT10S` |Timeout of authentication operations, where applicable. -This is a timeout for each operation (if there are retries, each timeout will be this duration). -Defaults to 10 seconds. - -Authentication operation timeout -|`authentication.config` |xref:{rootdir}/config/io_helidon_integrations_oci_ConfigMethodConfig.adoc[ConfigMethodConfig] |{nbsp} |Config method configuration (if provided and used). - -Information needed for config io.helidon.integrations.oci.OciConfig.authenticationMethod() -|`authentication.config-file` |xref:{rootdir}/config/io_helidon_integrations_oci_ConfigFileMethodConfig.adoc[ConfigFileMethodConfig] |{nbsp} |Config file method configuration (if provided and used). - -Information to customize config for io.helidon.integrations.oci.OciConfig.authenticationMethod() -|`authentication.session-token` |xref:{rootdir}/config/io_helidon_integrations_oci_SessionTokenMethodConfig.adoc[SessionTokenMethodConfig] |{nbsp} |Session token method configuration (if provided and used). - -Information to customize config for io.helidon.integrations.oci.OciConfig.authenticationMethod() -|`imds-base-uri` |URI |{nbsp} |The OCI IMDS URI (http URL pointing to the metadata service, if customization needed). - -The OCI IMDS URI -|`imds-detect-retries` |int |{nbsp} |Customize the number of retries to contact IMDS service. - -Number of retries, each provider has its own defaults -|`imds-timeout` |Duration |`PT1S` |The OCI IMDS connection timeout. This is used to auto-detect availability. - -This configuration property is used when attempting to connect to the metadata service. - -The OCI IMDS connection timeout -|`region` |Region |{nbsp} |Explicit region. The configured region will be used by region provider. -This may be ignored by authentication detail providers, as in most cases region is provided by them. - -Explicit region - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_SessionTokenMethodConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_integrations_oci_SessionTokenMethodConfig.adoc deleted file mode 100644 index f54e475e444..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_SessionTokenMethodConfig.adoc +++ /dev/null @@ -1,105 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.integrations.oci.SessionTokenMethodConfig -:keywords: helidon, config, io.helidon.integrations.oci.SessionTokenMethodConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.integrations.oci.SessionTokenMethodConfig -include::{rootdir}/includes/attributes.adoc[] - -= SessionTokenMethodConfig (integrations.oci) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.integrations.oci/io/helidon/integrations/oci/SessionTokenMethodConfig.html[io.helidon.integrations.oci.SessionTokenMethodConfig] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`fingerprint` |string |{nbsp} |The OCI authentication fingerprint. - -This configuration property must be provided in order to set the https://docs.oracle.com/en-us/iaas/Content/API/Concepts/apisigningkey.htm[API signing key's fingerprint]. -See com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getFingerprint() for more details. - -The OCI authentication fingerprint -|`initial-refresh-delay` |Duration |{nbsp} |Delay of the first refresh. -Defaults to 0, to refresh immediately (implemented in the authentication details provider). - -Initial refresh delay -See com.oracle.bmc.auth.SessionTokenAuthenticationDetailsProvider.SessionTokenAuthenticationDetailsProviderBuilder.initialRefreshDelay(long) -|`passphrase` |char[] |{nbsp} |The OCI authentication passphrase. - -This property must be provided in order to set the -com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getPassphraseCharacters(). - -The OCI authentication passphrase -|`private-key-path` |Path |{nbsp} |The OCI authentication private key resource. -A resource can be defined as a resource on classpath, file on the file system, -base64 encoded text value in config, or plain-text value in config. - -If not defined, we will use `".oci/sessions/DEFAULT/oci_api_key.pem` file in user home directory. - -The OCI authentication key file -|`refresh-period` |Duration |{nbsp} |Refresh period, i.e. how often refresh occurs. -Defaults to 55 minutes (implemented in the authentication details provider). - -Refresh period -See com.oracle.bmc.auth.SessionTokenAuthenticationDetailsProvider.SessionTokenAuthenticationDetailsProviderBuilder.refreshPeriod(long) -|`region` |string |{nbsp} |The OCI region. - -The OCI region -|`session-lifetime-hours` |long |{nbsp} |Maximal lifetime of a session. -Defaults to (and maximum is) 24 hours. -Can only be set to a lower value. - -Lifetime of a session in hours -|`session-token` |string |{nbsp} |Session token value. -If both this value, and sessionTokenPath() is defined, this value is used. - -Session token -|`session-token-path` |Path |{nbsp} |Session token path. -If both this value, and sessionToken() is defined, the value of sessionToken() is used. - -Session token path -|`tenant-id` |string |{nbsp} |The OCI tenant id. - -This property must be provided in order to set the -com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getTenantId(). - -The OCI tenant id -|`user-id` |string |{nbsp} |The OCI user id. - -This property must be provided in order to set the -com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getUserId(). - -The OCI user id - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_metrics_OciMetricsSupport.adoc b/docs/src/main/asciidoc/config/io_helidon_integrations_oci_metrics_OciMetricsSupport.adoc deleted file mode 100644 index 4a2ca3977e1..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_metrics_OciMetricsSupport.adoc +++ /dev/null @@ -1,72 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.integrations.oci.metrics.OciMetricsSupport -:keywords: helidon, config, io.helidon.integrations.oci.metrics.OciMetricsSupport -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.integrations.oci.metrics.OciMetricsSupport -include::{rootdir}/includes/attributes.adoc[] - -= OciMetricsSupport (integrations.oci.metrics) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.integrations.oci.metrics/io/helidon/integrations/oci/metrics/OciMetricsSupport.html[io.helidon.integrations.oci.metrics.OciMetricsSupport] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`batch-delay` |long |`1` |Sets the delay interval if metrics are posted in batches -(defaults to DEFAULT_BATCH_DELAY). -|`batch-size` |int |`50` |Sets the maximum no. of metrics to send in a batch -(defaults to DEFAULT_BATCH_SIZE). -|`compartment-id` |string |{nbsp} |Sets the compartment ID. -|`delay` |long |`60` |Sets the delay interval between metric posting -(defaults to DEFAULT_SCHEDULER_DELAY). -|`description-enabled` |boolean |`true` |Sets whether the description should be enabled or not. - - Defaults to `true`. - -|`enabled` |boolean |`true` |Sets whether metrics transmission to OCI is enabled. - - Defaults to `true`. - -|`initial-delay` |long |`1` |Sets the initial delay before metrics are sent to OCI -(defaults to DEFAULT_SCHEDULER_INITIAL_DELAY). -|`namespace` |string |{nbsp} |Sets the namespace. -|`resource-group` |string |{nbsp} |Sets the resource group. -|`scheduling-time-unit` |TimeUnit (NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS) |`TimeUnit.SECONDS` |Sets the time unit applied to the initial delay and delay values (defaults to `TimeUnit.SECONDS`). -|`scopes` |String[] |`All scopes` |Sets which metrics scopes (e.g., base, vendor, application) should be sent to OCI. - - If this method is never invoked, defaults to all scopes. - - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_sdk_runtime_OciConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_integrations_oci_sdk_runtime_OciConfig.adoc deleted file mode 100644 index ea125b939c9..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_sdk_runtime_OciConfig.adoc +++ /dev/null @@ -1,197 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.integrations.oci.sdk.runtime.OciConfig -:keywords: helidon, config, io.helidon.integrations.oci.sdk.runtime.OciConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.integrations.oci.sdk.runtime.OciConfig -include::{rootdir}/includes/attributes.adoc[] - -= OciConfig (integrations.oci.sdk.runtime) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.integrations.oci.sdk.runtime/io/helidon/integrations/oci/sdk/runtime/OciConfig.html[io.helidon.integrations.oci.sdk.runtime.OciConfig] - - -This is a standalone configuration type, prefix from configuration root: `oci` - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`auth-strategies` |string[] (auto, config, config-file, instance-principals, resource-principal) |{nbsp} |The list of authentication strategies that will be attempted by -com.oracle.bmc.auth.AbstractAuthenticationDetailsProvider when one is -called for. This is only used if authStrategy() is not present. - -- `auto` - if present in the list, or if no value - for this property exists. -- `config` - the - com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider - will be used, customized with other configuration - properties described here. -- `config-file` - the - com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider - will be used, customized with other configuration - properties described here. -- `instance-principals` - the - com.oracle.bmc.auth.InstancePrincipalsAuthenticationDetailsProvider - will be used. -- `resource-principal` - the - com.oracle.bmc.auth.ResourcePrincipalAuthenticationDetailsProvider - will be used. - -If there are more than one strategy descriptors defined, the -first one that is deemed to be available/suitable will be used and all others will be ignored. - -The list of authentication strategies that will be applied, defaulting to `auto` -See io.helidon.integrations.oci.sdk.runtime.OciAuthenticationDetailsProvider.AuthStrategy - -Allowed values: - -- `auto`: auto select first applicable -- `config`: simple authentication provider -- `config-file`: config file authentication provider -- `instance-principals`: instance principals authentication provider -- `resource-principal`: resource principal authentication provider - -|`auth-strategy` |string (auto, config, config-file, instance-principals, resource-principal) |{nbsp} |The singular authentication strategy to apply. This will be preferred over authStrategies() if both are -present. - -The singular authentication strategy to be applied - -Allowed values: - -- `auto`: auto select first applicable -- `config`: simple authentication provider -- `config-file`: config file authentication provider -- `instance-principals`: instance principals authentication provider -- `resource-principal`: resource principals authentication provider - -|`auth.fingerprint` |string |{nbsp} |The OCI authentication fingerprint. - -This configuration property has an effect only when `config` is, explicitly or implicitly, -present in the value for the authStrategies(). This is also known as simpleConfigIsPresent(). -When it is present, this property must be provided in order to set the https://docs.oracle.com/en-us/iaas/Content/API/Concepts/apisigningkey.htm[API signing key's fingerprint]. -See com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getFingerprint() for more details. - -The OCI authentication fingerprint -|`auth.keyFile` |string |`oci_api_key.pem` |The OCI authentication key file. - -This configuration property has an effect only when `config` is, explicitly or implicitly, -present in the value for the authStrategies(). This is also known as simpleConfigIsPresent(). -When it is present, this property must be provided in order to set the -com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getPrivateKey(). This file must exist in the -`user.home` directory. Alternatively, this property can be set using either authPrivateKey() or -using authPrivateKeyPath(). - -The OCI authentication key file -|`auth.passphrase` |char[] |{nbsp} |The OCI authentication passphrase. - -This configuration property has an effect only when `config` is, explicitly or implicitly, -present in the value for the authStrategies(). This is also known as simpleConfigIsPresent(). -When it is present, this property must be provided in order to set the -com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getPassphraseCharacters(). - -The OCI authentication passphrase -|`auth.private-key` |char[] |{nbsp} |The OCI authentication private key. - -This configuration property has an effect only when `config` is, explicitly or implicitly, -present in the value for the authStrategies(). This is also known as simpleConfigIsPresent(). -When it is present, this property must be provided in order to set the -com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getPrivateKey(). Alternatively, this property -can be set using either authKeyFile() residing in the `user.home` directory, or using -authPrivateKeyPath(). - -The OCI authentication private key -|`auth.private-key-path` |string |{nbsp} |The OCI authentication key file path. - -This configuration property has an effect only when `config` is, explicitly or implicitly, -present in the value for the authStrategies(). This is also known as simpleConfigIsPresent(). -When it is present, this property must be provided in order to set the -com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider.getPrivateKey(). This file path is -an alternative for using authKeyFile() where the file must exist in the `user.home` directory. -Alternatively, this property can be set using authPrivateKey(). - -The OCI authentication key file path -|`auth.region` |string |{nbsp} |The OCI region. - -This configuration property has an effect only when `config` is, explicitly or implicitly, -present in the value for the authStrategies(). This is also known as simpleConfigIsPresent(). -When it is present, either this property or com.oracle.bmc.auth.RegionProvider must be provide a value in order -to set the com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider.getRegion(). - -The OCI region -|`auth.tenant-id` |string |{nbsp} |The OCI tenant id. - -This configuration property has an effect only when `config` is, explicitly or implicitly, -present in the value for the authStrategies(). This is also known as simpleConfigIsPresent(). -When it is present, this property must be provided in order to set the -com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider.getTenantId(). - -The OCI tenant id -|`auth.user-id` |string |{nbsp} |The OCI user id. - -This configuration property has an effect only when `config` is, explicitly or implicitly, -present in the value for the authStrategies(). -When it is present, this property must be provided in order to set the -com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider.getUserId(). - -The OCI user id -|`config.path` |string |{nbsp} |The OCI configuration profile path. - -This configuration property has an effect only when `config-file` is, explicitly or implicitly, -present in the value for the authStrategies(). This is also known as fileConfigIsPresent(). -When it is present, this property must also be present and then the -com.oracle.bmc.ConfigFileReader.parse(String) -method will be passed this value. It is expected to be passed with a -valid OCI configuration file path. - -The OCI configuration profile path -|`config.profile` |string |`DEFAULT` |The OCI configuration/auth profile name. - -This configuration property has an effect only when `config-file` is, explicitly or implicitly, -present in the value for the authStrategies(). This is also known as fileConfigIsPresent(). -When it is present, this property may also be optionally provided in order to override the default -DEFAULT_PROFILE_NAME. - -The optional OCI configuration/auth profile name -|`imds.hostname` |string |`169.254.169.254` |The OCI IMDS hostname. - -This configuration property is used to identify the metadata service url. - -The OCI IMDS hostname -|`imds.timeout.milliseconds` |Duration |`PT0.1S` |The OCI IMDS connection timeout. This is used to auto-detect availability. - -This configuration property is used when attempting to connect to the metadata service. - -The OCI IMDS connection timeout -See OciAvailability - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_tls_certificates_OciCertificatesTlsManager.adoc b/docs/src/main/asciidoc/config/io_helidon_integrations_oci_tls_certificates_OciCertificatesTlsManager.adoc deleted file mode 100644 index e2727ce4d68..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_integrations_oci_tls_certificates_OciCertificatesTlsManager.adoc +++ /dev/null @@ -1,76 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.integrations.oci.tls.certificates.OciCertificatesTlsManager -:keywords: helidon, config, io.helidon.integrations.oci.tls.certificates.OciCertificatesTlsManager -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.integrations.oci.tls.certificates.OciCertificatesTlsManager -include::{rootdir}/includes/attributes.adoc[] - -= OciCertificatesTlsManager (integrations.oci.tls.certificates) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.integrations.oci.tls.certificates/io/helidon/integrations/oci/tls/certificates/OciCertificatesTlsManager.html[io.helidon.integrations.oci.tls.certificates.OciCertificatesTlsManager] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`ca-ocid` |string |{nbsp} |The Certificate Authority OCID. - -Certificate authority OCID -|`cert-ocid` |string |{nbsp} |The Certificate OCID. - -Certificate OCID -|`compartment-ocid` |string |{nbsp} |The OCID of the compartment the services are in. - -The compartment OCID -|`key-ocid` |string |{nbsp} |The Key OCID. - -Key OCID -|`key-password` |Supplier |{nbsp} |The Key password. - -Key password -|`schedule` |string |{nbsp} |The schedule for trigger a reload check, testing whether there is a new io.helidon.common.tls.Tls instance -available. - -The schedule for reload -|`vault-crypto-endpoint` |URI |{nbsp} |The address to use for the OCI Key Management Service / Vault crypto usage. -Each OCI Vault has public crypto and management endpoints. We need to specify the crypto endpoint of the vault we are -rotating the private keys in. The implementation expects both client and server to store the private key in the same vault. - -The address for the key management service / vault crypto usage -|`vault-management-endpoint` |URI |{nbsp} |The address to use for the OCI Key Management Service / Vault management usage. -The crypto endpoint of the vault we are rotating the private keys in. - -The address for the key management service / vault management usage - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_integrations_openapi_ui_OpenApiUi.adoc b/docs/src/main/asciidoc/config/io_helidon_integrations_openapi_ui_OpenApiUi.adoc deleted file mode 100644 index b03520e095d..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_integrations_openapi_ui_OpenApiUi.adoc +++ /dev/null @@ -1,57 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.integrations.openapi.ui.OpenApiUi -:keywords: helidon, config, io.helidon.integrations.openapi.ui.OpenApiUi -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.integrations.openapi.ui.OpenApiUi -include::{rootdir}/includes/attributes.adoc[] - -= OpenApiUi (integrations.openapi.ui) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.integrations.openapi.ui/io/helidon/integrations/openapi/ui/OpenApiUi.html[io.helidon.integrations.openapi.ui.OpenApiUi] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`enabled` |boolean |`true` |Sets whether the service should be enabled. - -`true` if enabled, `false` otherwise -|`options` |Map<string, string> |{nbsp} |Merges implementation-specific UI options. - -Options for the UI to merge -|`web-context` |string |{nbsp} |Full web context (not just the suffix). - -Full web context path - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_metrics_api_ComponentMetricsSettings.adoc b/docs/src/main/asciidoc/config/io_helidon_metrics_api_ComponentMetricsSettings.adoc deleted file mode 100644 index 11ce389bc8f..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_metrics_api_ComponentMetricsSettings.adoc +++ /dev/null @@ -1,55 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.metrics.api.ComponentMetricsSettings -:keywords: helidon, config, io.helidon.metrics.api.ComponentMetricsSettings -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.metrics.api.ComponentMetricsSettings -include::{rootdir}/includes/attributes.adoc[] - -= ComponentMetricsSettings (metrics.api) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.metrics.api/io/helidon/metrics/api/ComponentMetricsSettings.html[io.helidon.metrics.api.ComponentMetricsSettings] - - -[source,text] -.Config key ----- -metrics ----- - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`enabled` |boolean |{nbsp} |Sets whether metrics should be enabled for the component. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_metrics_api_KeyPerformanceIndicatorMetricsConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_metrics_api_KeyPerformanceIndicatorMetricsConfig.adoc deleted file mode 100644 index 9b1de363e07..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_metrics_api_KeyPerformanceIndicatorMetricsConfig.adoc +++ /dev/null @@ -1,54 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.metrics.api.KeyPerformanceIndicatorMetricsConfig -:keywords: helidon, config, io.helidon.metrics.api.KeyPerformanceIndicatorMetricsConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.metrics.api.KeyPerformanceIndicatorMetricsConfig -include::{rootdir}/includes/attributes.adoc[] - -= KeyPerformanceIndicatorMetricsConfig (metrics.api) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.metrics.api/io/helidon/metrics/api/KeyPerformanceIndicatorMetricsConfig.html[io.helidon.metrics.api.KeyPerformanceIndicatorMetricsConfig] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`extended` |boolean |`false` |Whether KPI extended metrics are enabled. - -True if KPI extended metrics are enabled; false otherwise -|`long-running-requests.threshold` |Duration |`PT10S` |Threshold in ms that characterizes whether a request is long running. - -Threshold in ms indicating a long-running request - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_metrics_api_MetricsConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_metrics_api_MetricsConfig.adoc deleted file mode 100644 index 154b8c1c7c0..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_metrics_api_MetricsConfig.adoc +++ /dev/null @@ -1,92 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.metrics.api.MetricsConfig -:keywords: helidon, config, io.helidon.metrics.api.MetricsConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.metrics.api.MetricsConfig -include::{rootdir}/includes/attributes.adoc[] - -= MetricsConfig (metrics.api) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.metrics.api/io/helidon/metrics/api/MetricsConfig.html[io.helidon.metrics.api.MetricsConfig] - - -This is a standalone configuration type, prefix from configuration root: `metrics` - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`app-name` |string |{nbsp} |Value for the application tag to be added to each meter ID. - -Application tag value -|`app-tag-name` |string |{nbsp} |Name for the application tag to be added to each meter ID. - -Application tag name -|`enabled` |boolean |`true` |Whether metrics functionality is enabled. - -If metrics are configured to be enabled -|[.line-through]#`gc-time-type`# |GcTimeType (GAUGE, COUNTER) |`GcTimeType.COUNTER` |*Deprecated* Whether the `gc.time` meter should be registered as a gauge (vs. a counter). -The `gc.time` meter is inspired by the MicroProfile Metrics spec, in which the meter was originally checked to -be a counter but starting in 5.1 was checked be a gauge. For the duration of Helidon 4.x users can choose which -type of meter Helidon registers for `gc.time`. -The type of meter to use for registering `gc.time` -@deprecated Provided for backward compatibility only; no replacement - -Allowed values: - -- `GAUGE`: Implement the meter as a gauge. This is backward-incompatible with Helidon 4.0.x releases but complies with -MicroProfile 5.1. -- `COUNTER`: Implement the meter as a counter. This is backward-compatible with Helidon 4.0.x releases but does not comply with -MicroProfile 5.1. - -|`key-performance-indicators` |xref:{rootdir}/config/io_helidon_metrics_api_KeyPerformanceIndicatorMetricsConfig.adoc[KeyPerformanceIndicatorMetricsConfig] |{nbsp} |Key performance indicator metrics settings. - -Key performance indicator metrics settings -|`permit-all` |boolean |`true` |Whether to allow anybody to access the endpoint. - -Whether to permit access to metrics endpoint to anybody, defaults to `true` -See roles() -|`rest-request-enabled` |boolean |`false` |Whether automatic REST request metrics should be measured. - -True/false -|`roles` |string[] |`observe` |Hints for role names the user is expected to be in. - -List of hints -|`scoping` |xref:{rootdir}/config/io_helidon_metrics_api_ScopingConfig.adoc[ScopingConfig] |{nbsp} |Settings related to scoping management. - -Scoping settings -|`tags` |xref:{rootdir}/config/io_helidon_metrics_api_Tag.adoc[Tag[]] |{nbsp} |Global tags. - -Name/value pairs for global tags - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_metrics_api_ScopeConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_metrics_api_ScopeConfig.adoc deleted file mode 100644 index 633a78c55d2..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_metrics_api_ScopeConfig.adoc +++ /dev/null @@ -1,60 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.metrics.api.ScopeConfig -:keywords: helidon, config, io.helidon.metrics.api.ScopeConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.metrics.api.ScopeConfig -include::{rootdir}/includes/attributes.adoc[] - -= ScopeConfig (metrics.api) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.metrics.api/io/helidon/metrics/api/ScopeConfig.html[io.helidon.metrics.api.ScopeConfig] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`enabled` |boolean |`true` |Whether the scope is enabled. - -If the scope is enabled -|`filter.exclude` |Pattern |{nbsp} |Regular expression for meter names to exclude. - -Exclude expression -|`filter.include` |Pattern |{nbsp} |Regular expression for meter names to include. - -Include expression -|`name` |string |{nbsp} |Name of the scope to which the configuration applies. - -Scope name - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_metrics_api_ScopingConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_metrics_api_ScopingConfig.adoc deleted file mode 100644 index 66647f2d924..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_metrics_api_ScopingConfig.adoc +++ /dev/null @@ -1,58 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.metrics.api.ScopingConfig -:keywords: helidon, config, io.helidon.metrics.api.ScopingConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.metrics.api.ScopingConfig -include::{rootdir}/includes/attributes.adoc[] - -= ScopingConfig (metrics.api) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.metrics.api/io/helidon/metrics/api/ScopingConfig.html[io.helidon.metrics.api.ScopingConfig] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`default` |string |`application` |Default scope value to associate with meters that are registered without an explicit setting; no setting means meters -are assigned scope io.helidon.metrics.api.Meter.Scope.DEFAULT. - -Default scope value -|`scopes` |xref:{rootdir}/config/io_helidon_metrics_api_ScopeConfig.adoc[Map<string, ScopeConfig>] |{nbsp} |Settings for individual scopes. - -Scope settings -|`tag-name` |string |`scope` |Tag name for storing meter scope values in the underlying implementation meter registry. - -Tag name for storing scope values - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_metrics_api_Tag.adoc b/docs/src/main/asciidoc/config/io_helidon_metrics_api_Tag.adoc deleted file mode 100644 index c21e086f50a..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_metrics_api_Tag.adoc +++ /dev/null @@ -1,39 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.metrics.api.Tag -:keywords: helidon, config, io.helidon.metrics.api.Tag -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.metrics.api.Tag -include::{rootdir}/includes/attributes.adoc[] - -= Tag (metrics.api) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.metrics.api/io/helidon/metrics/api/Tag.html[io.helidon.metrics.api.Tag] - - - - -== Configuration options - - - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_microprofile_jwt_auth_JwtAuthProvider.adoc b/docs/src/main/asciidoc/config/io_helidon_microprofile_jwt_auth_JwtAuthProvider.adoc deleted file mode 100644 index fe409f265d9..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_microprofile_jwt_auth_JwtAuthProvider.adoc +++ /dev/null @@ -1,90 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.microprofile.jwt.auth.JwtAuthProvider -:keywords: helidon, config, io.helidon.microprofile.jwt.auth.JwtAuthProvider -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.microprofile.jwt.auth.JwtAuthProvider -include::{rootdir}/includes/attributes.adoc[] - -= JwtAuthProvider (microprofile.jwt.auth) Configuration - -// tag::config[] - -MP-JWT Auth configuration is defined by the spec (options prefixed with `mp.jwt.`), and we add a few configuration options for the security provider (options prefixed with `security.providers.mp-jwt-auth.`) - - -Type: link:{javadoc-base-url}/io.helidon.microprofile.jwt.auth/io/helidon/microprofile/jwt/auth/JwtAuthProvider.html[io.helidon.microprofile.jwt.auth.JwtAuthProvider] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`mp.jwt.decrypt.key.algorithm` |string (RSA-OAEP, RSA-OAEP-256) |{nbsp} |Expected key management algorithm supported by the MP JWT endpoint. -Supported algorithms are either `RSA-OAEP` or `RSA-OAEP-256`. -If no algorithm is set, both algorithms must be accepted. - -Allowed values: - -- `RSA-OAEP`: RSA-OAEP Algorithm -- `RSA-OAEP-256`: RSA-OAEP-256 Algorithm - -|`mp.jwt.decrypt.key.location` |string |{nbsp} |Private key for decryption of encrypted claims. -The value may be a relative path or a URL. -|`mp.jwt.token.cookie` |string |`Bearer` |Specific cookie property name where we should search for JWT property. -|`mp.jwt.token.header` |string |`Authorization` |Name of the header expected to contain the token. -|`mp.jwt.verify.audiences` |string[] |{nbsp} |Expected audiences of incoming tokens. -|`mp.jwt.verify.clock.skew` |int |`5` |Clock skew to be accounted for in token expiration and max age validations in seconds. -|`mp.jwt.verify.issuer` |string |{nbsp} |Expected issuer in incoming requests. -|`mp.jwt.verify.publickey` |string |{nbsp} |String representation of the public key. -|`mp.jwt.verify.publickey.location` |string |{nbsp} |Path to public key. -The value may be a relative path or a URL. -|`mp.jwt.verify.token.age` |int |{nbsp} |Maximal expected token age in seconds. If this value is set, `iat` claim needs to be present in the JWT. -|`security.providers.mp-jwt-auth.allow-impersonation` |boolean |`false` |Whether to allow impersonation by explicitly overriding -username from outbound requests using io.helidon.security.EndpointConfig.PROPERTY_OUTBOUND_ID -property. -By default this is not allowed and identity can only be propagated. -|`security.providers.mp-jwt-auth.atn-token.default-key-id` |string |{nbsp} |Default JWT key ID which should be used. -|`security.providers.mp-jwt-auth.atn-token.handler` |xref:{rootdir}/config/io_helidon_security_util_TokenHandler.adoc[TokenHandler] |{nbsp} |Token handler to extract username from request. -Uses `Authorization` header with `bearer ` prefix by default. -|`security.providers.mp-jwt-auth.atn-token.jwk.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |JWK resource for authenticating the request -|`security.providers.mp-jwt-auth.atn-token.jwt-audience` |string |{nbsp} |Audience expected in inbound JWTs. -|`security.providers.mp-jwt-auth.atn-token.verify-key` |string |{nbsp} |Path to public key. -The value may be a relative path or a URL. -|`security.providers.mp-jwt-auth.authenticate` |boolean |`true` |Whether to authenticate requests. -|`security.providers.mp-jwt-auth.load-on-startup` |boolean |`false` |Whether to load JWK verification keys on server startup -Default value is `false`. -|`security.providers.mp-jwt-auth.optional` |boolean |`false` |Whether authentication is required. -By default, request will fail if the username cannot be extracted. -If set to false, request will process and this provider will abstain. -|`security.providers.mp-jwt-auth.principal-type` |SubjectType (USER, SERVICE) |`USER` |Principal type this provider extracts (and also propagates). -|`security.providers.mp-jwt-auth.propagate` |boolean |`true` |Whether to propagate identity. -|`security.providers.mp-jwt-auth.sign-token` |xref:{rootdir}/config/io_helidon_security_providers_common_OutboundConfig.adoc[OutboundConfig] |{nbsp} |Configuration of outbound rules. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_microprofile_lra_Coordinator.adoc b/docs/src/main/asciidoc/config/io_helidon_microprofile_lra_Coordinator.adoc deleted file mode 100644 index 6a39dea6fe2..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_microprofile_lra_Coordinator.adoc +++ /dev/null @@ -1,51 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2022, 2023 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. - -/////////////////////////////////////////////////////////////////////////////// - -//MANUALLY CREATED DOCUMENT - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io_helidon_microprofile_lra_Coordinator -:keywords: helidon, io_helidon_microprofile_lra_Coordinator -:basic-table-intro: The table below lists the configuration keys that configure io_helidon_microprofile_lra_Coordinator -include::{rootdir}/includes/attributes.adoc[] - -= LRA Configuration - -// tag::config[] - -[source,text] -.Type ----- -io.helidon.microprofile.lra ----- - -.Optional configuration options -[cols="3,3,2,5a"] - -|=== -|Key |Type |Default value |Description - -|`mp.lra.coordinator.url` |string |`\http://localhost:8070/lra-coordinator` |Url of coordinator. -|`mp.lra.coordinator.propagation.active` |boolean |{nbsp} |Propagate LRA headers `LRA_HTTP_CONTEXT_HEADER` and `LRA_HTTP_PARENT_CONTEXT_HEADER` through non-LRA endpoints. -|`mp.lara.participant.url` |string |{nbsp} |Url of the LRA enabled service overrides standard base uri, so coordinator can call load-balancer instead of the service. -|`mp.lra.coordinator.timeout` |string |{nbsp} |Timeout for synchronous communication with coordinator. -|`mp.lra.coordinator.timeout-unit` |string |{nbsp} |Timeout unit for synchronous communication with coordinator. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_microprofile_openapi_MpOpenApiManagerConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_microprofile_openapi_MpOpenApiManagerConfig.adoc deleted file mode 100644 index fdc573009bf..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_microprofile_openapi_MpOpenApiManagerConfig.adoc +++ /dev/null @@ -1,52 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.microprofile.openapi.MpOpenApiManagerConfig -:keywords: helidon, config, io.helidon.microprofile.openapi.MpOpenApiManagerConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.microprofile.openapi.MpOpenApiManagerConfig -include::{rootdir}/includes/attributes.adoc[] - -= MpOpenApiManagerConfig (microprofile.openapi) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.microprofile.openapi/io/helidon/microprofile/openapi/MpOpenApiManagerConfig.html[io.helidon.microprofile.openapi.MpOpenApiManagerConfig] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`mp.openapi.extensions.helidon.use-jaxrs-semantics` |boolean |{nbsp} |If `true` and the `jakarta.ws.rs.core.Application` class returns a non-empty set, endpoints defined by -other resources are not included in the OpenAPI document. - -`true` if enabled, `false` otherwise - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_microprofile_server_Server.adoc b/docs/src/main/asciidoc/config/io_helidon_microprofile_server_Server.adoc deleted file mode 100644 index d592b6f36d7..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_microprofile_server_Server.adoc +++ /dev/null @@ -1,54 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.microprofile.server.Server -:keywords: helidon, config, io.helidon.microprofile.server.Server -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.microprofile.server.Server -include::{rootdir}/includes/attributes.adoc[] - -= Server (microprofile.server) Configuration - -// tag::config[] - -Configuration of Helidon Microprofile Server - - -Type: link:{javadoc-base-url}/io.helidon.microprofile.server/io/helidon/microprofile/server/Server.html[io.helidon.microprofile.server.Server] - - -This is a standalone configuration type, prefix from configuration root: `server` - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`host` |string |{nbsp} |Configure listen host. -|`port` |int |{nbsp} |Configure listen port. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_openapi_OpenApiFeature.adoc b/docs/src/main/asciidoc/config/io_helidon_openapi_OpenApiFeature.adoc deleted file mode 100644 index 275d8a67a84..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_openapi_OpenApiFeature.adoc +++ /dev/null @@ -1,86 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.openapi.OpenApiFeature -:keywords: helidon, config, io.helidon.openapi.OpenApiFeature -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.openapi.OpenApiFeature -include::{rootdir}/includes/attributes.adoc[] - -= OpenApiFeature (openapi) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.openapi/io/helidon/openapi/OpenApiFeature.html[io.helidon.openapi.OpenApiFeature] - - -This is a standalone configuration type, prefix from configuration root: `openapi` - - -This type provides the following service implementations: - -- `io.helidon.webserver.spi.ServerFeatureProvider` - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`cors` |xref:{rootdir}/config/io_helidon_cors_CrossOriginConfig.adoc[CrossOriginConfig] |{nbsp} |CORS config. - -CORS config -|`enabled` |boolean |`true` |Sets whether the feature should be enabled. - -`true` if enabled, `false` otherwise -|`manager` |io.helidon.openapi.OpenApiManager (service provider interface) |{nbsp} |OpenAPI manager. - -The OpenAPI manager -|`permit-all` |boolean |`true` |Whether to allow anybody to access the endpoint. - -Whether to permit access to metrics endpoint to anybody, defaults to `true` -See roles() -|`roles` |string[] |`openapi` |Hints for role names the user is expected to be in. - -List of hints -|`services` |io.helidon.openapi.OpenApiService[] (service provider interface) |{nbsp} |OpenAPI services. - -The OpenAPI services -|`sockets` |string[] |{nbsp} |List of sockets to register this feature on. If empty, it would get registered on all sockets. - -Socket names to register on, defaults to empty (all available sockets) -|`static-file` |string |{nbsp} |Path of the static OpenAPI document file. Default types are `json`, `yaml`, and `yml`. - -Location of the static OpenAPI document file -|`web-context` |string |`/openapi` |Web context path for the OpenAPI endpoint. - -WebContext to use -|`weight` |double |`90.0` |Weight of the OpenAPI feature. This is quite low, to be registered after routing. -io.helidon.openapi.OpenApiFeature.WEIGHT. - -Weight of the feature - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_scheduling_Cron.adoc b/docs/src/main/asciidoc/config/io_helidon_scheduling_Cron.adoc deleted file mode 100644 index f69f9df6925..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_scheduling_Cron.adoc +++ /dev/null @@ -1,69 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.scheduling.Cron -:keywords: helidon, config, io.helidon.scheduling.Cron -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.scheduling.Cron -include::{rootdir}/includes/attributes.adoc[] - -= Cron (scheduling) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.scheduling/io/helidon/scheduling/Cron.html[io.helidon.scheduling.Cron] - - - - -== Configuration options - -.Required configuration options -[cols="3,3a,2,5a"] -|=== -|key |type |default value |description - -|`expression` |string |{nbsp} |Cron expression for specifying period of execution. - -*Examples:* - -- `0/2 * * * * ? *` - Every 2 seconds -- `0 45 9 ? * *` - Every day at 9:45 -- `0 15 8 ? * MON-FRI` - Every workday at 8:15 - -Cron expression - -|=== - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`concurrent` |boolean |`true` |Allow concurrent execution if previous task didn't finish before next execution. -Default value is `true`. - -True for allow concurrent execution. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_scheduling_FixedRate.adoc b/docs/src/main/asciidoc/config/io_helidon_scheduling_FixedRate.adoc deleted file mode 100644 index d494d3bcb7e..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_scheduling_FixedRate.adoc +++ /dev/null @@ -1,82 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.scheduling.FixedRate -:keywords: helidon, config, io.helidon.scheduling.FixedRate -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.scheduling.FixedRate -include::{rootdir}/includes/attributes.adoc[] - -= FixedRate (scheduling) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.scheduling/io/helidon/scheduling/FixedRate.html[io.helidon.scheduling.FixedRate] - - - - -== Configuration options - -.Required configuration options -[cols="3,3a,2,5a"] -|=== -|key |type |default value |description - -|`delay` |long |{nbsp} |Fixed rate delay between each invocation. Time unit is by default java.util.concurrent.TimeUnit.SECONDS, -can be specified with io.helidon.scheduling.FixedRateConfig.Builder.timeUnit(java.util.concurrent.TimeUnit). - -Delay between each invocation - -|=== - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`delay-type` |DelayType (SINCE_PREVIOUS_START, SINCE_PREVIOUS_END) |`DelayType.SINCE_PREVIOUS_START` |Configure whether the delay between the invocations should be calculated from the time when previous task started or ended. -Delay type is by default FixedRate.DelayType.SINCE_PREVIOUS_START. - -Delay type - -Allowed values: - -- `SINCE_PREVIOUS_START`: Next invocation delay is measured from the previous invocation task start. -- `SINCE_PREVIOUS_END`: Next invocation delay is measured from the previous invocation task end. - -|`initial-delay` |long |`0` |Initial delay of the first invocation. Time unit is by default java.util.concurrent.TimeUnit.SECONDS, -can be specified with -io.helidon.scheduling.FixedRateConfig.Builder.timeUnit(java.util.concurrent.TimeUnit) timeUnit(). - -Initial delay value -|`time-unit` |TimeUnit (NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS) |`TimeUnit.TimeUnit.SECONDS` |java.util.concurrent.TimeUnit TimeUnit used for interpretation of values provided with -io.helidon.scheduling.FixedRateConfig.Builder.delay(long) -and io.helidon.scheduling.FixedRateConfig.Builder.initialDelay(long). - -Time unit for interpreting values - in io.helidon.scheduling.FixedRateConfig.Builder.delay(long) - and io.helidon.scheduling.FixedRateConfig.Builder.initialDelay(long) - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_scheduling_TaskConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_scheduling_TaskConfig.adoc deleted file mode 100644 index 3325c5b3606..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_scheduling_TaskConfig.adoc +++ /dev/null @@ -1,39 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.scheduling.TaskConfig -:keywords: helidon, config, io.helidon.scheduling.TaskConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.scheduling.TaskConfig -include::{rootdir}/includes/attributes.adoc[] - -= TaskConfig (scheduling) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.scheduling/io/helidon/scheduling/TaskConfig.html[io.helidon.scheduling.TaskConfig] - - - - -== Configuration options - - - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_security_Security.adoc b/docs/src/main/asciidoc/config/io_helidon_security_Security.adoc deleted file mode 100644 index dc0be6f755b..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_security_Security.adoc +++ /dev/null @@ -1,106 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.security.Security -:keywords: helidon, config, io.helidon.security.Security -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.security.Security -include::{rootdir}/includes/attributes.adoc[] - -= Security (security) Configuration - -// tag::config[] - -Configuration of security providers, integration and other security options - - -Type: link:{javadoc-base-url}/io.helidon.security/io/helidon/security/Security.html[io.helidon.security.Security] - - -This is a standalone configuration type, prefix from configuration root: `security` - - - -== Configuration options - -.Required configuration options -[cols="3,3a,2,5a"] -|=== -|key |type |default value |description - -|`providers` |io.helidon.security.spi.SecurityProvider[] (service provider interface) - -Such as: - - - xref:{rootdir}/config/io_helidon_security_providers_idcs_mapper_IdcsRoleMapperProvider.adoc[idcs-role-mapper (IdcsRoleMapperProvider)] - - xref:{rootdir}/config/io_helidon_security_providers_config_vault_ConfigVaultProvider.adoc[config-vault (ConfigVaultProvider)] - - xref:{rootdir}/config/io_helidon_security_providers_jwt_JwtProvider.adoc[jwt (JwtProvider)] - - xref:{rootdir}/config/io_helidon_security_providers_httpauth_HttpBasicAuthProvider.adoc[http-basic-auth (HttpBasicAuthProvider)] - - xref:{rootdir}/config/io_helidon_security_providers_idcs_mapper_IdcsMtRoleMapperProvider.adoc[idcs-role-mapper (IdcsMtRoleMapperProvider)] - - xref:{rootdir}/config/io_helidon_security_providers_google_login_GoogleTokenProvider.adoc[google-login (GoogleTokenProvider)] - - xref:{rootdir}/config/io_helidon_security_providers_oidc_OidcProvider.adoc[oidc (OidcProvider)] - - xref:{rootdir}/config/io_helidon_security_providers_httpauth_HttpDigestAuthProvider.adoc[http-digest-auth (HttpDigestAuthProvider)] - - xref:{rootdir}/config/io_helidon_security_providers_header_HeaderAtnProvider.adoc[header-atn (HeaderAtnProvider)] - - xref:{rootdir}/config/io_helidon_security_providers_abac_AbacProvider.adoc[abac (AbacProvider)] - - |{nbsp} |Add a provider, works as addProvider(io.helidon.security.spi.SecurityProvider, String), where the name is set -to `Class#getSimpleName()`. - -|=== - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`default-authentication-provider` |string (service provider interface) |{nbsp} |ID of the default authentication provider -|`default-authorization-provider` |string |{nbsp} |ID of the default authorization provider -|`enabled` |boolean |`true` |Security can be disabled using configuration, or explicitly. -By default, security instance is enabled. -Disabled security instance will not perform any checks and allow -all requests. -|`environment.server-time` |xref:{rootdir}/config/io_helidon_security_SecurityTime.adoc[SecurityTime] |{nbsp} |Server time to use when evaluating security policies that depend on time. -|`provider-policy.class-name` |Class |{nbsp} |Provider selection policy class name, only used when type is set to CLASS -|`provider-policy.type` |ProviderSelectionPolicyType (FIRST, COMPOSITE, CLASS) |`FIRST` |Type of the policy. - -Allowed values: - -- `FIRST`: Choose first provider from the list by default. -Choose provider with the name defined when explicit provider requested. -- `COMPOSITE`: Can compose multiple providers together to form a single -logical provider. -- `CLASS`: Explicit class for a custom ProviderSelectionPolicyType. - -|`secrets` |Map<string, string> (documented for specific cases) |{nbsp} |Configured secrets -|`secrets.*.config` |io.helidon.security.SecretsProviderConfig (service provider interface) - -Such as: - - - xref:{rootdir}/config/io_helidon_security_providers_config_vault_ConfigVaultProvider_SecretConfig.adoc[SecretConfig] - - |{nbsp} |Configuration specific to the secret provider -|`secrets.*.name` |string |{nbsp} |Name of the secret, used for lookup -|`secrets.*.provider` |string |{nbsp} |Name of the secret provider -|`tracing.enabled` |boolean |`true` |Whether or not tracing should be enabled. If set to false, security tracer will be a no-op tracer. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_security_SecurityTime.adoc b/docs/src/main/asciidoc/config/io_helidon_security_SecurityTime.adoc deleted file mode 100644 index a5b7eeab695..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_security_SecurityTime.adoc +++ /dev/null @@ -1,60 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.security.SecurityTime -:keywords: helidon, config, io.helidon.security.SecurityTime -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.security.SecurityTime -include::{rootdir}/includes/attributes.adoc[] - -= SecurityTime (security) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.security/io/helidon/security/SecurityTime.html[io.helidon.security.SecurityTime] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`day-of-month` |long |{nbsp} |Set an explicit value for one of the time fields (such as ChronoField.YEAR). -|`hour-of-day` |long |{nbsp} |Set an explicit value for one of the time fields (such as ChronoField.YEAR). -|`millisecond` |long |{nbsp} |Set an explicit value for one of the time fields (such as ChronoField.YEAR). -|`minute` |long |{nbsp} |Set an explicit value for one of the time fields (such as ChronoField.YEAR). -|`month` |long |{nbsp} |Set an explicit value for one of the time fields (such as ChronoField.YEAR). -|`second` |long |{nbsp} |Set an explicit value for one of the time fields (such as ChronoField.YEAR). -|`shift-by-seconds` |long |`0` |Configure a time-shift in seconds, to move the current time to past or future. -|`time-zone` |ZoneId |{nbsp} |Override current time zone. The time will represent the SAME instant, in an explicit timezone. - -If we are in a UTC time zone and you set the timezone to "Europe/Prague", the time will be shifted by the offset -of Prague (e.g. if it is noon right now in UTC, you would get 14:00). -|`year` |long |{nbsp} |Set an explicit value for one of the time fields (such as ChronoField.YEAR). - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_abac_AbacProvider.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_abac_AbacProvider.adoc deleted file mode 100644 index 138c31dd3da..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_abac_AbacProvider.adoc +++ /dev/null @@ -1,63 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.security.providers.abac.AbacProvider -:keywords: helidon, config, io.helidon.security.providers.abac.AbacProvider -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.security.providers.abac.AbacProvider -include::{rootdir}/includes/attributes.adoc[] - -= AbacProvider (security.providers.abac) Configuration - -// tag::config[] - -Attribute Based Access Control provider - - -Type: link:{javadoc-base-url}/io.helidon.security.providers.abac/io/helidon/security/providers/abac/AbacProvider.html[io.helidon.security.providers.abac.AbacProvider] - - -[source,text] -.Config key ----- -abac ----- - - -This type provides the following service implementations: - -- `io.helidon.security.spi.SecurityProvider` -- `io.helidon.security.spi.AuthorizationProvider` - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`fail-if-none-validated` |boolean |`true` |Whether to fail if NONE of the attributes is validated. -|`fail-on-unvalidated` |boolean |`true` |Whether to fail if any attribute is left unvalidated. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_common_EvictableCache.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_common_EvictableCache.adoc deleted file mode 100644 index bc02a878aed..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_common_EvictableCache.adoc +++ /dev/null @@ -1,59 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.security.providers.common.EvictableCache -:keywords: helidon, config, io.helidon.security.providers.common.EvictableCache -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.security.providers.common.EvictableCache -include::{rootdir}/includes/attributes.adoc[] - -= EvictableCache (security.providers.common) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.security.providers.common/io/helidon/security/providers/common/EvictableCache.html[io.helidon.security.providers.common.EvictableCache] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`cache-enabled` |boolean |`true` |If the cacheEnabled is set to false, no caching will be done. -Otherwise (default behavior) evictable caching will be used. -|`cache-evict-delay-millis` |long |`60000` |Delay from the creation of the cache to first eviction -|`cache-evict-period-millis` |long |`300000` |How often to evict records -|`cache-overall-timeout-millis` |long |`3600000` |Configure record timeout since its creation. -|`cache-timeout-millis` |long |`3600000` |Configure record timeout since last access. -|`evictor-class` |Class |{nbsp} |Configure evictor to check if a record is still valid. -This should be a fast way to check, as it is happening in a ConcurrentHashMap.forEachKey(long, Consumer). -This is also called during all get and remove operations to only return valid records. -|`max-size` |long |`100000` |Configure maximal cache size. -|`parallelism-threshold` |long |`10000` |Configure parallelism threshold. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_common_OutboundConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_common_OutboundConfig.adoc deleted file mode 100644 index e2773d0b843..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_common_OutboundConfig.adoc +++ /dev/null @@ -1,51 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.security.providers.common.OutboundConfig -:keywords: helidon, config, io.helidon.security.providers.common.OutboundConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.security.providers.common.OutboundConfig -include::{rootdir}/includes/attributes.adoc[] - -= OutboundConfig (security.providers.common) Configuration - -// tag::config[] - -Outbound configuration for outbound security - - -Type: link:{javadoc-base-url}/io.helidon.security.providers.common/io/helidon/security/providers/common/OutboundConfig.html[io.helidon.security.providers.common.OutboundConfig] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`outbound` |xref:{rootdir}/config/io_helidon_security_providers_common_OutboundTarget.adoc[OutboundTarget[]] |{nbsp} |Add a new target configuration. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_common_OutboundTarget.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_common_OutboundTarget.adoc deleted file mode 100644 index 3c9e2cec3b0..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_common_OutboundTarget.adoc +++ /dev/null @@ -1,87 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.security.providers.common.OutboundTarget -:keywords: helidon, config, io.helidon.security.providers.common.OutboundTarget -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.security.providers.common.OutboundTarget -include::{rootdir}/includes/attributes.adoc[] - -= OutboundTarget (security.providers.common) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.security.providers.common/io/helidon/security/providers/common/OutboundTarget.html[io.helidon.security.providers.common.OutboundTarget] - - - - -== Configuration options - -.Required configuration options -[cols="3,3a,2,5a"] -|=== -|key |type |default value |description - -|`name` |string |{nbsp} |Configure the name of this outbound target. - -|=== - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`hosts` |string[] |{nbsp} |Add supported host for this target. May be called more than once to add more hosts. - -Valid examples: - -- localhost - -- www.google.com - -- 127.0.0.1 - -- *.oracle.com - -- 192.169.*.* - -- *.google.* - - -|`methods` |string[] |{nbsp} |Add supported method for this target. May be called more than once to add more methods. -The method is tested as is ignoring case against the used method. -|`paths` |string[] |{nbsp} |Add supported paths for this target. May be called more than once to add more paths. -The path is tested as is against called path, and also tested as a regular expression. -|`transport` |string[] |{nbsp} |Add supported transports for this target. May be called more than once to add more transports. - -Valid examples: - -- http - -- https - -There is no wildcard support - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_config_vault_ConfigVaultProvider.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_config_vault_ConfigVaultProvider.adoc deleted file mode 100644 index 02fe4a1679e..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_config_vault_ConfigVaultProvider.adoc +++ /dev/null @@ -1,64 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.security.providers.config.vault.ConfigVaultProvider -:keywords: helidon, config, io.helidon.security.providers.config.vault.ConfigVaultProvider -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.security.providers.config.vault.ConfigVaultProvider -include::{rootdir}/includes/attributes.adoc[] - -= ConfigVaultProvider (security.providers.config.vault) Configuration - -// tag::config[] - -Secrets and Encryption provider using just configuration - - -Type: link:{javadoc-base-url}/io.helidon.security.providers.config.vault/io/helidon/security/providers/config/vault/ConfigVaultProvider.html[io.helidon.security.providers.config.vault.ConfigVaultProvider] - - -[source,text] -.Config key ----- -config-vault ----- - - -This type provides the following service implementations: - -- `io.helidon.security.spi.SecurityProvider` -- `io.helidon.security.spi.SecretsProvider` -- `io.helidon.security.spi.EncryptionProvider` - - -== Configuration options - -.Required configuration options -[cols="3,3a,2,5a"] -|=== -|key |type |default value |description - -|`master-password` |string |{nbsp} |Configure master password used for encryption/decryption. -If master password cannot be obtained from any source (this method, configuration, system property, -environment variable), encryption and decryption will not be supported. - -|=== - - - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_config_vault_ConfigVaultProvider_SecretConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_config_vault_ConfigVaultProvider_SecretConfig.adoc deleted file mode 100644 index 604012e420c..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_config_vault_ConfigVaultProvider_SecretConfig.adoc +++ /dev/null @@ -1,55 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.security.providers.config.vault.ConfigVaultProvider.SecretConfig -:keywords: helidon, config, io.helidon.security.providers.config.vault.ConfigVaultProvider.SecretConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.security.providers.config.vault.ConfigVaultProvider.SecretConfig -include::{rootdir}/includes/attributes.adoc[] - -= SecretConfig (security.providers.config.vault.ConfigVaultProvider) Configuration - -// tag::config[] - -Provider of secrets defined in configuration itself - - -Type: link:{javadoc-base-url}/io.helidon.security.providers.config.vault.ConfigVaultProvider/io/helidon/security/providers/config/vault/ConfigVaultProvider/SecretConfig.html[io.helidon.security.providers.config.vault.ConfigVaultProvider.SecretConfig] - - - -This type provides the following service implementations: - -- `io.helidon.security.SecretsProviderConfig` - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`value` |ConfiguredOption |{nbsp} |Value of the secret, can be a reference to another configuration key, such as ${app.secret} - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_google_login_GoogleTokenProvider.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_google_login_GoogleTokenProvider.adoc deleted file mode 100644 index 245347d4c51..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_google_login_GoogleTokenProvider.adoc +++ /dev/null @@ -1,70 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.security.providers.google.login.GoogleTokenProvider -:keywords: helidon, config, io.helidon.security.providers.google.login.GoogleTokenProvider -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.security.providers.google.login.GoogleTokenProvider -include::{rootdir}/includes/attributes.adoc[] - -= GoogleTokenProvider (security.providers.google.login) Configuration - -// tag::config[] - -Google Authentication provider - - -Type: link:{javadoc-base-url}/io.helidon.security.providers.google.login/io/helidon/security/providers/google/login/GoogleTokenProvider.html[io.helidon.security.providers.google.login.GoogleTokenProvider] - - -[source,text] -.Config key ----- -google-login ----- - - -This type provides the following service implementations: - -- `io.helidon.security.spi.SecurityProvider` -- `io.helidon.security.spi.AuthenticationProvider` - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`client-id` |string |{nbsp} |Google application client id, to validate that the token was generated by Google for us. -|`optional` |boolean |`false` |If set to true, this provider will return io.helidon.security.SecurityResponse.SecurityStatus.ABSTAIN instead -of failing in case of invalid request. -|`outbound` |xref:{rootdir}/config/io_helidon_security_providers_common_OutboundConfig.adoc[OutboundConfig] |{nbsp} |Outbound configuration - a set of outbound targets that -will have the token propagated. -|`proxy-host` |string |{nbsp} |Set proxy host when talking to Google. -|`proxy-port` |int |`80` |Set proxy port when talking to Google. -|`realm` |string |`helidon` |Set the authentication realm to build challenge, defaults to "helidon". -|`token` |xref:{rootdir}/config/io_helidon_security_util_TokenHandler.adoc[TokenHandler] |``Authorization` header with `bearer` prefix` |Token provider to extract Google access token from request, defaults to "Authorization" header with a "bearer " prefix. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_header_HeaderAtnProvider.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_header_HeaderAtnProvider.adoc deleted file mode 100644 index 9ab2b5c1863..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_header_HeaderAtnProvider.adoc +++ /dev/null @@ -1,71 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.security.providers.header.HeaderAtnProvider -:keywords: helidon, config, io.helidon.security.providers.header.HeaderAtnProvider -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.security.providers.header.HeaderAtnProvider -include::{rootdir}/includes/attributes.adoc[] - -= HeaderAtnProvider (security.providers.header) Configuration - -// tag::config[] - -Security provider that extracts a username (or service name) from a header. - - -Type: link:{javadoc-base-url}/io.helidon.security.providers.header/io/helidon/security/providers/header/HeaderAtnProvider.html[io.helidon.security.providers.header.HeaderAtnProvider] - - -[source,text] -.Config key ----- -header-atn ----- - - -This type provides the following service implementations: - -- `io.helidon.security.spi.SecurityProvider` -- `io.helidon.security.spi.AuthenticationProvider` - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`atn-token` |xref:{rootdir}/config/io_helidon_security_util_TokenHandler.adoc[TokenHandler] |{nbsp} |Token handler to extract username from request. -|`authenticate` |boolean |`true` |Whether to authenticate requests. -|`optional` |boolean |`false` |Whether authentication is required. -By default, request will fail if the username cannot be extracted. -If set to false, request will process and this provider will abstain. -|`outbound` |xref:{rootdir}/config/io_helidon_security_providers_common_OutboundTarget.adoc[OutboundTarget[]] |{nbsp} |Configure outbound target for identity propagation. -|`outbound-token` |xref:{rootdir}/config/io_helidon_security_util_TokenHandler.adoc[TokenHandler] |{nbsp} |Token handler to create outbound headers to propagate identity. -If not defined, atnTokenHandler will be used. -|`principal-type` |SubjectType (USER, SERVICE) |`USER` |Principal type this provider extracts (and also propagates). -|`propagate` |boolean |`false` |Whether to propagate identity. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_httpauth_ConfigUserStore_ConfigUser.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_httpauth_ConfigUserStore_ConfigUser.adoc deleted file mode 100644 index 2080a93a359..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_httpauth_ConfigUserStore_ConfigUser.adoc +++ /dev/null @@ -1,51 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.security.providers.httpauth.ConfigUserStore.ConfigUser -:keywords: helidon, config, io.helidon.security.providers.httpauth.ConfigUserStore.ConfigUser -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.security.providers.httpauth.ConfigUserStore.ConfigUser -include::{rootdir}/includes/attributes.adoc[] - -= ConfigUser (security.providers.httpauth.ConfigUserStore) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.security.providers.httpauth.ConfigUserStore/io/helidon/security/providers/httpauth/ConfigUserStore/ConfigUser.html[io.helidon.security.providers.httpauth.ConfigUserStore.ConfigUser] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`login` |string |{nbsp} |User's login -|`password` |string |{nbsp} |User's password -|`roles` |string[] |{nbsp} |List of roles the user is in - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_httpauth_HttpBasicAuthProvider.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_httpauth_HttpBasicAuthProvider.adoc deleted file mode 100644 index 0e902bbef34..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_httpauth_HttpBasicAuthProvider.adoc +++ /dev/null @@ -1,69 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.security.providers.httpauth.HttpBasicAuthProvider -:keywords: helidon, config, io.helidon.security.providers.httpauth.HttpBasicAuthProvider -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.security.providers.httpauth.HttpBasicAuthProvider -include::{rootdir}/includes/attributes.adoc[] - -= HttpBasicAuthProvider (security.providers.httpauth) Configuration - -// tag::config[] - -HTTP Basic Authentication provider - - -Type: link:{javadoc-base-url}/io.helidon.security.providers.httpauth/io/helidon/security/providers/httpauth/HttpBasicAuthProvider.html[io.helidon.security.providers.httpauth.HttpBasicAuthProvider] - - -[source,text] -.Config key ----- -http-basic-auth ----- - - -This type provides the following service implementations: - -- `io.helidon.security.spi.SecurityProvider` -- `io.helidon.security.spi.AuthenticationProvider` - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`optional` |boolean |`false` |Whether authentication is required. -By default, request will fail if the authentication cannot be verified. -If set to false, request will process and this provider will abstain. -|`outbound` |xref:{rootdir}/config/io_helidon_security_providers_common_OutboundTarget.adoc[OutboundTarget[]] |{nbsp} |Add a new outbound target to configure identity propagation or explicit username/password. -|`principal-type` |SubjectType (USER, SERVICE) |`USER` |Principal type this provider extracts (and also propagates). -|`realm` |string |`helidon` |Set the realm to use when challenging users. -|`users` |xref:{rootdir}/config/io_helidon_security_providers_httpauth_ConfigUserStore_ConfigUser.adoc[ConfigUser[]] |{nbsp} |Set user store to validate users. -Removes any other stores added through addUserStore(SecureUserStore). - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_httpauth_HttpDigestAuthProvider.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_httpauth_HttpDigestAuthProvider.adoc deleted file mode 100644 index 12711830dc1..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_httpauth_HttpDigestAuthProvider.adoc +++ /dev/null @@ -1,89 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.security.providers.httpauth.HttpDigestAuthProvider -:keywords: helidon, config, io.helidon.security.providers.httpauth.HttpDigestAuthProvider -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.security.providers.httpauth.HttpDigestAuthProvider -include::{rootdir}/includes/attributes.adoc[] - -= HttpDigestAuthProvider (security.providers.httpauth) Configuration - -// tag::config[] - -Http digest authentication security provider - - -Type: link:{javadoc-base-url}/io.helidon.security.providers.httpauth/io/helidon/security/providers/httpauth/HttpDigestAuthProvider.html[io.helidon.security.providers.httpauth.HttpDigestAuthProvider] - - -[source,text] -.Config key ----- -http-digest-auth ----- - - -This type provides the following service implementations: - -- `io.helidon.security.spi.SecurityProvider` -- `io.helidon.security.spi.AuthenticationProvider` - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`algorithm` |Algorithm (MD5) |`MD5` |Digest algorithm to use. - -Allowed values: - -- `MD5`: MD5 algorithm. - -|`nonce-timeout-millis` |long |`86400000` |How long will the nonce value be valid. When timed-out, browser will re-request username/password. -|`optional` |boolean |`false` |Whether authentication is required. -By default, request will fail if the authentication cannot be verified. -If set to false, request will process and this provider will abstain. -|`principal-type` |SubjectType (USER, SERVICE) |`USER` |Principal type this provider extracts (and also propagates). -|`qop` |Qop (NONE, AUTH) |`NONE` |Only `AUTH` supported. If left empty, uses the legacy approach (older RFC version). `AUTH-INT` is not supported. - -Allowed values: - -- `NONE`: Legacy approach - used internally to parse headers. Do not use this option when -building provider. If you want to support only legacy RFC, please use -HttpDigestAuthProvider.Builder.noDigestQop(). -Only AUTH is supported, as auth-int requires access to message body. -- `AUTH`: QOP "auth" - stands for "authentication". - -|`realm` |string |`Helidon` |Set the realm to use when challenging users. -|`server-secret` |string |{nbsp} |The nonce is encrypted using this secret - to make sure the nonce we get back was generated by us and to -make sure we can safely time-out nonce values. -This secret must be the same for all service instances (or all services that want to share the same authentication). -Defaults to a random password - e.g. if deployed to multiple servers, the authentication WILL NOT WORK. You MUST -provide your own password to work in a distributed environment with non-sticky load balancing. -|`users` |xref:{rootdir}/config/io_helidon_security_providers_httpauth_ConfigUserStore_ConfigUser.adoc[ConfigUser[]] |{nbsp} |Set user store to obtain passwords and roles based on logins. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_httpsign_HttpSignProvider.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_httpsign_HttpSignProvider.adoc deleted file mode 100644 index ebbab063bf8..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_httpsign_HttpSignProvider.adoc +++ /dev/null @@ -1,150 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.security.providers.httpsign.HttpSignProvider -:keywords: helidon, config, io.helidon.security.providers.httpsign.HttpSignProvider -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.security.providers.httpsign.HttpSignProvider -include::{rootdir}/includes/attributes.adoc[] - -= HttpSignProvider (security.providers.httpsign) Configuration - -// tag::config[] - -HTTP header signature provider. - - -Type: link:{javadoc-base-url}/io.helidon.security.providers.httpsign/io/helidon/security/providers/httpsign/HttpSignProvider.html[io.helidon.security.providers.httpsign.HttpSignProvider] - - -[source,text] -.Config key ----- -http-signatures ----- - - -This type provides the following service implementations: - -- `io.helidon.security.spi.AuthenticationProvider` - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`backward-compatible-eol` |boolean |`false` |Enable support for Helidon versions before 3.0.0 (exclusive). - -Until version 3.0.0 (exclusive) there was a trailing end of line added to the signed -data. -To be able to communicate cross versions, we must configure this when talking to older versions of Helidon. -Default value is `false`. In Helidon 2.x, this switch exists as well and the default is `true`, to -allow communication between versions as needed. -|`headers` |HttpSignHeader[] (SIGNATURE, AUTHORIZATION, CUSTOM) |{nbsp} |Add a header that is validated on inbound requests. Provider may support more than -one header to validate. - -Allowed values: - -- `SIGNATURE`: Creates (or validates) a "Signature" header. -- `AUTHORIZATION`: Creates (or validates) an "Authorization" header, that contains "Signature" as the -beginning of its content (the rest of the header is the same as for SIGNATURE. -- `CUSTOM`: Custom provided using a io.helidon.security.util.TokenHandler. - -|`inbound.keys` |xref:{rootdir}/config/io_helidon_security_providers_httpsign_InboundClientDefinition.adoc[InboundClientDefinition[]] |{nbsp} |Add inbound configuration. This is used to validate signature and authenticate the -party. - -The same can be done through configuration: - ----- - -{ - name = "http-signatures" - class = "HttpSignProvider" - http-signatures { - inbound { - # This configures the InboundClientDefinition - keys: [ - { - key-id = "service1" - hmac.secret = "${CLEAR=password}" - }] - } - } -} - ----- - -|`optional` |boolean |`true` |Set whether the signature is optional. If set to true (default), this provider will -SecurityResponse.SecurityStatus.ABSTAIN from this request if signature is not -present. If set to false, this provider will SecurityResponse.SecurityStatus.FAILURE fail -if signature is not present. -|`outbound` |xref:{rootdir}/config/io_helidon_security_providers_common_OutboundConfig.adoc[OutboundConfig] |{nbsp} |Add outbound targets to this builder. -The targets are used to chose what to do for outbound communication. -The targets should have OutboundTargetDefinition attached through -OutboundTarget.Builder.customObject(Class, Object) to tell us how to sign -the request. - -The same can be done through configuration: - ----- - -{ - name = "http-signatures" - class = "HttpSignProvider" - http-signatures { - targets: [ - { - name = "service2" - hosts = ["localhost"] - paths = ["/service2/.*"] - - # This configures the OutboundTargetDefinition - signature { - key-id = "service1" - hmac.secret = "${CLEAR=password}" - } - }] - } -} - ----- - -|`realm` |string |`helidon` |Realm to use for challenging inbound requests that do not have "Authorization" header -in case header is HttpSignHeader.AUTHORIZATION and singatures are not optional. -|`sign-headers` |xref:{rootdir}/config/io_helidon_security_providers_httpsign_SignedHeadersConfig_HeadersConfig.adoc[HeadersConfig[]] |{nbsp} |Override the default inbound required headers (e.g. headers that MUST be signed and -headers that MUST be signed IF present). - -Defaults: - -- get, head, delete methods: date, (request-target), host are mandatory; authorization if present (unless we are -creating/validating the HttpSignHeader.AUTHORIZATION ourselves -- put, post: same as above, with addition of: content-length, content-type and digest if present - -- for other methods: date, (request-target) - -Note that this provider DOES NOT validate the "Digest" HTTP header, only the signature. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_httpsign_InboundClientDefinition.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_httpsign_InboundClientDefinition.adoc deleted file mode 100644 index 43c503610e3..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_httpsign_InboundClientDefinition.adoc +++ /dev/null @@ -1,61 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.security.providers.httpsign.InboundClientDefinition -:keywords: helidon, config, io.helidon.security.providers.httpsign.InboundClientDefinition -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.security.providers.httpsign.InboundClientDefinition -include::{rootdir}/includes/attributes.adoc[] - -= InboundClientDefinition (security.providers.httpsign) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.security.providers.httpsign/io/helidon/security/providers/httpsign/InboundClientDefinition.html[io.helidon.security.providers.httpsign.InboundClientDefinition] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`algorithm` |string |{nbsp} |Algorithm of signature used by this client. -Currently supported: - -- rsa-sha256 - asymmetric based on public/private keys -- hmac-sha256 - symmetric based on a shared secret - - -|`hmac.secret` |string |{nbsp} |Helper method to configure a password-like secret (instead of byte based hmacSecret(byte[]). -The password is transformed to bytes with StandardCharsets.UTF_8 charset. -|`key-id` |string |{nbsp} |The key id of this client to map to this signature validation configuration. -|`principal-name` |string |{nbsp} |The principal name of the client, defaults to keyId if not configured. -|`principal-type` |SubjectType (USER, SERVICE) |`SERVICE` |The type of principal we have authenticated (either user or service, defaults to service). -|`public-key` |xref:{rootdir}/config/io_helidon_common_pki_Keys.adoc[Keys] |{nbsp} |For algorithms based on public/private key (such as rsa-sha256), this provides access to the public key of the client. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_httpsign_SignedHeadersConfig_HeadersConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_httpsign_SignedHeadersConfig_HeadersConfig.adoc deleted file mode 100644 index 27a60dad950..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_httpsign_SignedHeadersConfig_HeadersConfig.adoc +++ /dev/null @@ -1,51 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.security.providers.httpsign.SignedHeadersConfig.HeadersConfig -:keywords: helidon, config, io.helidon.security.providers.httpsign.SignedHeadersConfig.HeadersConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.security.providers.httpsign.SignedHeadersConfig.HeadersConfig -include::{rootdir}/includes/attributes.adoc[] - -= HeadersConfig (security.providers.httpsign.SignedHeadersConfig) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.security.providers.httpsign.SignedHeadersConfig/io/helidon/security/providers/httpsign/SignedHeadersConfig/HeadersConfig.html[io.helidon.security.providers.httpsign.SignedHeadersConfig.HeadersConfig] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`always` |string[] |{nbsp} |Headers that must be signed (and signature validation or creation should fail if not signed or present) -|`if-present` |string[] |{nbsp} |Headers that must be signed if present in request. -|`method` |string |{nbsp} |HTTP method this header configuration is bound to. If not present, it is considered default header configuration. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_idcs_mapper_IdcsMtRoleMapperProvider.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_idcs_mapper_IdcsMtRoleMapperProvider.adoc deleted file mode 100644 index af72a410d6c..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_idcs_mapper_IdcsMtRoleMapperProvider.adoc +++ /dev/null @@ -1,76 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.security.providers.idcs.mapper.IdcsMtRoleMapperProvider -:keywords: helidon, config, io.helidon.security.providers.idcs.mapper.IdcsMtRoleMapperProvider -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.security.providers.idcs.mapper.IdcsMtRoleMapperProvider -include::{rootdir}/includes/attributes.adoc[] - -= IdcsMtRoleMapperProvider (security.providers.idcs.mapper) Configuration - -// tag::config[] - -Multitenant IDCS role mapping provider - - -Type: link:{javadoc-base-url}/io.helidon.security.providers.idcs.mapper/io/helidon/security/providers/idcs/mapper/IdcsMtRoleMapperProvider.html[io.helidon.security.providers.idcs.mapper.IdcsMtRoleMapperProvider] - - -[source,text] -.Config key ----- -idcs-role-mapper ----- - - -This type provides the following service implementations: - -- `io.helidon.security.spi.SecurityProvider` -- `io.helidon.security.spi.SubjectMappingProvider` - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`cache-config` |xref:{rootdir}/config/io_helidon_security_providers_common_EvictableCache.adoc[EvictableCache] |{nbsp} |Use explicit io.helidon.security.providers.common.EvictableCache for role caching. -|`default-idcs-subject-type` |string |`user` |Configure subject type to use when requesting roles from IDCS. -Can be either IDCS_SUBJECT_TYPE_USER or IDCS_SUBJECT_TYPE_CLIENT. -Defaults to IDCS_SUBJECT_TYPE_USER. -|`idcs-app-name-handler` |xref:{rootdir}/config/io_helidon_security_util_TokenHandler.adoc[TokenHandler] |{nbsp} |Configure token handler for IDCS Application name. -By default the header IdcsMtRoleMapperProvider.IDCS_APP_HEADER is used. -|`idcs-tenant-handler` |xref:{rootdir}/config/io_helidon_security_util_TokenHandler.adoc[TokenHandler] |{nbsp} |Configure token handler for IDCS Tenant ID. -By default the header IdcsMtRoleMapperProvider.IDCS_TENANT_HEADER is used. -|`oidc-config` |xref:{rootdir}/config/io_helidon_security_providers_oidc_common_OidcConfig.adoc[OidcConfig] |{nbsp} |Use explicit io.helidon.security.providers.oidc.common.OidcConfig instance, e.g. when using it also for OIDC -provider. -|`subject-types` |SubjectType[] (USER, SERVICE) |`USER` |Add a supported subject type. -If none added, io.helidon.security.SubjectType.USER is used. -If any added, only the ones added will be used (e.g. if you want to use -both io.helidon.security.SubjectType.USER and io.helidon.security.SubjectType.SERVICE, -both need to be added. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_idcs_mapper_IdcsRoleMapperProvider.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_idcs_mapper_IdcsRoleMapperProvider.adoc deleted file mode 100644 index 528642bc210..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_idcs_mapper_IdcsRoleMapperProvider.adoc +++ /dev/null @@ -1,72 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.security.providers.idcs.mapper.IdcsRoleMapperProvider -:keywords: helidon, config, io.helidon.security.providers.idcs.mapper.IdcsRoleMapperProvider -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.security.providers.idcs.mapper.IdcsRoleMapperProvider -include::{rootdir}/includes/attributes.adoc[] - -= IdcsRoleMapperProvider (security.providers.idcs.mapper) Configuration - -// tag::config[] - -IDCS role mapping provider - - -Type: link:{javadoc-base-url}/io.helidon.security.providers.idcs.mapper/io/helidon/security/providers/idcs/mapper/IdcsRoleMapperProvider.html[io.helidon.security.providers.idcs.mapper.IdcsRoleMapperProvider] - - -[source,text] -.Config key ----- -idcs-role-mapper ----- - - -This type provides the following service implementations: - -- `io.helidon.security.spi.SecurityProvider` -- `io.helidon.security.spi.SubjectMappingProvider` - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`cache-config` |xref:{rootdir}/config/io_helidon_security_providers_common_EvictableCache.adoc[EvictableCache] |{nbsp} |Use explicit io.helidon.security.providers.common.EvictableCache for role caching. -|`default-idcs-subject-type` |string |`user` |Configure subject type to use when requesting roles from IDCS. -Can be either IDCS_SUBJECT_TYPE_USER or IDCS_SUBJECT_TYPE_CLIENT. -Defaults to IDCS_SUBJECT_TYPE_USER. -|`oidc-config` |xref:{rootdir}/config/io_helidon_security_providers_oidc_common_OidcConfig.adoc[OidcConfig] |{nbsp} |Use explicit io.helidon.security.providers.oidc.common.OidcConfig instance, e.g. when using it also for OIDC -provider. -|`subject-types` |SubjectType[] (USER, SERVICE) |`USER` |Add a supported subject type. -If none added, io.helidon.security.SubjectType.USER is used. -If any added, only the ones added will be used (e.g. if you want to use -both io.helidon.security.SubjectType.USER and io.helidon.security.SubjectType.SERVICE, -both need to be added. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_idcs_mapper_IdcsRoleMapperProviderBase_Builder.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_idcs_mapper_IdcsRoleMapperProviderBase_Builder.adoc deleted file mode 100644 index 546e355da16..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_idcs_mapper_IdcsRoleMapperProviderBase_Builder.adoc +++ /dev/null @@ -1,58 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.security.providers.idcs.mapper.IdcsRoleMapperProviderBase.Builder -:keywords: helidon, config, io.helidon.security.providers.idcs.mapper.IdcsRoleMapperProviderBase.Builder -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.security.providers.idcs.mapper.IdcsRoleMapperProviderBase.Builder -include::{rootdir}/includes/attributes.adoc[] - -= Builder (security.providers.idcs.mapper.IdcsRoleMapperProviderBase) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.security.providers.idcs.mapper.IdcsRoleMapperProviderBase/io/helidon/security/providers/idcs/mapper/IdcsRoleMapperProviderBase/Builder.html[io.helidon.security.providers.idcs.mapper.IdcsRoleMapperProviderBase.Builder] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`default-idcs-subject-type` |string |`user` |Configure subject type to use when requesting roles from IDCS. -Can be either IDCS_SUBJECT_TYPE_USER or IDCS_SUBJECT_TYPE_CLIENT. -Defaults to IDCS_SUBJECT_TYPE_USER. -|`oidc-config` |xref:{rootdir}/config/io_helidon_security_providers_oidc_common_OidcConfig.adoc[OidcConfig] |{nbsp} |Use explicit io.helidon.security.providers.oidc.common.OidcConfig instance, e.g. when using it also for OIDC -provider. -|`subject-types` |SubjectType[] (USER, SERVICE) |`USER` |Add a supported subject type. -If none added, io.helidon.security.SubjectType.USER is used. -If any added, only the ones added will be used (e.g. if you want to use -both io.helidon.security.SubjectType.USER and io.helidon.security.SubjectType.SERVICE, -both need to be added. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_jwt_JwtProvider.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_jwt_JwtProvider.adoc deleted file mode 100644 index 92528b33934..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_jwt_JwtProvider.adoc +++ /dev/null @@ -1,90 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.security.providers.jwt.JwtProvider -:keywords: helidon, config, io.helidon.security.providers.jwt.JwtProvider -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.security.providers.jwt.JwtProvider -include::{rootdir}/includes/attributes.adoc[] - -= JwtProvider (security.providers.jwt) Configuration - -// tag::config[] - -JWT authentication provider - - -Type: link:{javadoc-base-url}/io.helidon.security.providers.jwt/io/helidon/security/providers/jwt/JwtProvider.html[io.helidon.security.providers.jwt.JwtProvider] - - -[source,text] -.Config key ----- -jwt ----- - - -This type provides the following service implementations: - -- `io.helidon.security.spi.SecurityProvider` -- `io.helidon.security.spi.AuthenticationProvider` - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`allow-impersonation` |boolean |`false` |Whether to allow impersonation by explicitly overriding -username from outbound requests using io.helidon.security.EndpointConfig.PROPERTY_OUTBOUND_ID -property. -By default this is not allowed and identity can only be propagated. -|`allow-unsigned` |boolean |`false` |Configure support for unsigned JWT. -If this is set to `true` any JWT that has algorithm -set to `none` and no `kid` defined will be accepted. -Note that this has serious security impact - if JWT can be sent - from a third party, this allows the third party to send ANY JWT - and it would be accpted as valid. -|`atn-token.handler` |xref:{rootdir}/config/io_helidon_security_util_TokenHandler.adoc[TokenHandler] |{nbsp} |Token handler to extract username from request. -|`atn-token.jwk.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |JWK resource used to verify JWTs created by other parties. -|`atn-token.jwt-audience` |string |{nbsp} |Audience expected in inbound JWTs. -|`atn-token.verify-signature` |boolean |`true` |Configure whether to verify signatures. -Signatures verification is enabled by default. You can configure the provider -not to verify signatures. - -*Make sure your service is properly secured on network level and only accessible from a secure endpoint that provides the JWTs when signature verification is disabled. If signature verification is disabled, this service will accept _ANY_ JWT* -|`authenticate` |boolean |`true` |Whether to authenticate requests. -|`optional` |boolean |`false` |Whether authentication is required. -By default, request will fail if the username cannot be extracted. -If set to false, request will process and this provider will abstain. -|`principal-type` |SubjectType (USER, SERVICE) |`USER` |Principal type this provider extracts (and also propagates). -|`propagate` |boolean |`true` |Whether to propagate identity. -|`sign-token` |xref:{rootdir}/config/io_helidon_security_providers_common_OutboundConfig.adoc[OutboundConfig] |{nbsp} |Configuration of outbound rules. -|`sign-token.jwk.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |JWK resource used to sign JWTs created by us. -|`sign-token.jwt-issuer` |string |{nbsp} |Issuer used to create new JWTs. -|`use-jwt-groups` |boolean |`true` |Claim `groups` from JWT will be used to automatically add - groups to current subject (may be used with jakarta.annotation.security.RolesAllowed annotation). - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_OidcProvider.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_OidcProvider.adoc deleted file mode 100644 index 5316da19bab..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_OidcProvider.adoc +++ /dev/null @@ -1,249 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.security.providers.oidc.OidcProvider -:keywords: helidon, config, io.helidon.security.providers.oidc.OidcProvider -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.security.providers.oidc.OidcProvider -include::{rootdir}/includes/attributes.adoc[] - -= OidcProvider (security.providers.oidc) Configuration - -// tag::config[] - -Open ID Connect security provider - - -Type: link:{javadoc-base-url}/io.helidon.security.providers.oidc/io/helidon/security/providers/oidc/OidcProvider.html[io.helidon.security.providers.oidc.OidcProvider] - - -[source,text] -.Config key ----- -oidc ----- - - -This type provides the following service implementations: - -- `io.helidon.security.spi.AuthenticationProvider` -- `io.helidon.security.spi.SecurityProvider` - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`access-token-ip-check` |boolean |`true` |Whether to check if current IP address matches the one access token was issued for. -This check helps with cookie replay attack prevention. -|`audience` |string |{nbsp} |Audience of issued tokens. -|`authorization-endpoint-uri` |URI |{nbsp} |URI of an authorization endpoint used to redirect users to for logging-in. - -If not defined, it is obtained from oidcMetadata(Resource), if that is not defined -an attempt is made to use identityUri(URI)/oauth2/v1/authorize. -|`base-scopes` |string |`openid` |Configure base scopes. -By default, this is DEFAULT_BASE_SCOPES. -If scope has a qualifier, it must be used here. -|`check-audience` |boolean |`false` |Configure audience claim check. -|`client-id` |string |{nbsp} |Client ID as generated by OIDC server. -|`client-secret` |string |{nbsp} |Client secret as generated by OIDC server. -Used to authenticate this application with the server when requesting -JWT based on a code. -|`client-timeout-millis` |Duration |`30000` |Timeout of calls using web client. -|`cookie-domain` |string |{nbsp} |Domain the cookie is valid for. -Not used by default. -|`cookie-encryption-enabled` |boolean |`false` |Whether to encrypt token cookie created by this microservice. -Defaults to `false`. -|`cookie-encryption-id-enabled` |boolean |`true` |Whether to encrypt id token cookie created by this microservice. -Defaults to `true`. -|`cookie-encryption-name` |string |{nbsp} |Name of the encryption configuration available through Security.encrypt(String, byte[]) and -Security.decrypt(String, String). -If configured and encryption is enabled for any cookie, -Security MUST be configured in global or current `io.helidon.common.context.Context` (this -is done automatically in Helidon MP). -|`cookie-encryption-password` |char[] |{nbsp} |Master password for encryption/decryption of cookies. This must be configured to the same value on each microservice -using the cookie. -|`cookie-encryption-refresh-enabled` |boolean |`true` |Whether to encrypt refresh token cookie created by this microservice. -Defaults to `true`. -|`cookie-encryption-state-enabled` |boolean |`true` |Whether to encrypt state cookie created by this microservice. -Defaults to `true`. -|`cookie-encryption-tenant-enabled` |boolean |`true` |Whether to encrypt tenant name cookie created by this microservice. -Defaults to `true`. -|`cookie-http-only` |boolean |`true` |When using cookie, if set to true, the HttpOnly attribute will be configured. -Defaults to OidcCookieHandler.Builder.DEFAULT_HTTP_ONLY. -|`cookie-max-age-seconds` |long |{nbsp} |When using cookie, used to set MaxAge attribute of the cookie, defining how long -the cookie is valid. -Not used by default. -|`cookie-name` |string |`JSESSIONID` |Name of the cookie to use. -Defaults to DEFAULT_COOKIE_NAME. -|`cookie-name-id-token` |string |`JSESSIONID_2` |Name of the cookie to use for id token. -Defaults to DEFAULT_COOKIE_NAME_2. - -This cookie is only used when logout is enabled, as otherwise it is not needed. -Content of this cookie is encrypted. -|`cookie-name-refresh-token` |string |`JSESSIONID_3` |The name of the cookie to use for the refresh token. -Defaults to DEFAULT_REFRESH_COOKIE_NAME. -|`cookie-name-state` |string |`JSESSIONID_3` |The name of the cookie to use for the state storage. -Defaults to DEFAULT_STATE_COOKIE_NAME. -|`cookie-name-tenant` |string |`HELIDON_TENANT` |The name of the cookie to use for the tenant name. -Defaults to DEFAULT_TENANT_COOKIE_NAME. -|`cookie-path` |string |`/` |Path the cookie is valid for. -Defaults to "/". -|`cookie-same-site` |SameSite (LAX, STRICT, NONE) |`LAX` |When using cookie, used to set the SameSite cookie value. Can be -"Strict" or "Lax". -|`cookie-secure` |boolean |`false` |When using cookie, if set to true, the Secure attribute will be configured. -Defaults to false. -|`cookie-use` |boolean |`true` |Whether to use cookie to store JWT between requests. -Defaults to DEFAULT_COOKIE_USE. -|`cors` |xref:{rootdir}/config/io_helidon_cors_CrossOriginConfig.adoc[CrossOriginConfig] |{nbsp} |Assign cross-origin resource sharing settings. -|`force-https-redirects` |boolean |`false` |Force HTTPS for redirects to identity provider. -Defaults to `false`. -|`frontend-uri` |string |{nbsp} |Full URI of this application that is visible from user browser. -Used to redirect request back from identity server after successful login. -|`header-token` |xref:{rootdir}/config/io_helidon_security_util_TokenHandler.adoc[TokenHandler] |{nbsp} |A TokenHandler to -process header containing a JWT. -Default is "Authorization" header with a prefix "bearer ". -|`header-use` |boolean |`true` |Whether to expect JWT in a header field. -|`id-token-signature-validation` |boolean |`true` |Whether id token signature check should be enabled. -Signature check is enabled by default, and it is highly recommended to not change that. -Change this setting only when you really know what you are doing, otherwise it could case security issues. -|`identity-uri` |URI |{nbsp} |URI of the identity server, base used to retrieve OIDC metadata. -|`introspect-endpoint-uri` |URI |{nbsp} |Endpoint to use to validate JWT. -Either use this or set signJwk(JwkKeys) or signJwk(Resource). -|`issuer` |string |{nbsp} |Issuer of issued tokens. -|`max-redirects` |int |`5` |Configure maximal number of redirects when redirecting to an OIDC provider within a single authentication -attempt. - -Defaults to DEFAULT_MAX_REDIRECTS -|`oidc-metadata-well-known` |boolean |`true` |If set to true, metadata will be loaded from default (well known) -location, unless it is explicitly defined using oidc-metadata-resource. If set to false, it would not be loaded -even if oidc-metadata-resource is not defined. In such a case all URIs must be explicitly defined (e.g. -token-endpoint-uri). -|`oidc-metadata.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Resource configuration for OIDC Metadata -containing endpoints to various identity services, as well as information about the identity server. -|`optional` |boolean |`false` |Whether authentication is required. -By default, request will fail if the authentication cannot be verified. -If set to true, request will process and this provider will abstain. -|`optional-audience` |boolean |`false` |Allow audience claim to be optional. -|`outbound` |xref:{rootdir}/config/io_helidon_security_providers_common_OutboundTarget.adoc[OutboundTarget[]] |{nbsp} |Add a new target configuration. -|`propagate` |boolean |`false` |Whether to propagate identity. -|`proxy-host` |string |{nbsp} |Proxy host to use. When defined, triggers usage of proxy for HTTP requests. -Setting to empty String has the same meaning as setting to null - disables proxy. -|`proxy-port` |int |`80` |Proxy port. -Defaults to DEFAULT_PROXY_PORT -|`proxy-protocol` |string |`http` |Proxy protocol to use when proxy is used. -Defaults to DEFAULT_PROXY_PROTOCOL. -|`query-id-token-param-name` |string |`id_token` |Name of a query parameter that contains the JWT id token when parameter is used. -|`query-param-name` |string |`accessToken` |Name of a query parameter that contains the JWT access token when parameter is used. -|`query-param-tenant-name` |string |`h_tenant` |Name of a query parameter that contains the tenant name when the parameter is used. -Defaults to DEFAULT_TENANT_PARAM_NAME. -|`query-param-use` |boolean |`false` |Whether to use a query parameter to send JWT token from application to this -server. -|`redirect` |boolean |`false` |By default, the client should redirect to the identity server for the user to log in. -This behavior can be overridden by setting redirect to false. When token is not present in the request, the client -will not redirect and just return appropriate error response code. -|`redirect-attempt-param` |string |`h_ra` |Configure the parameter used to store the number of attempts in redirect. - -Defaults to DEFAULT_ATTEMPT_PARAM -|`redirect-uri` |string |`/oidc/redirect` |URI to register web server component on, used by the OIDC server to -redirect authorization requests to after a user logs in or approves -scopes. -Note that usually the redirect URI configured here must be the -same one as configured on OIDC server. - -Defaults to DEFAULT_REDIRECT_URI -|`relative-uris` |boolean |`false` |Can be set to `true` to force the use of relative URIs in all requests, -regardless of the presence or absence of proxies or no-proxy lists. By default, -requests that use the Proxy will have absolute URIs. Set this flag to `true` -if the host is unable to accept absolute URIs. -Defaults to DEFAULT_RELATIVE_URIS. -|`scope-audience` |string |{nbsp} |Audience of the scope required by this application. This is prefixed to -the scope name when requesting scopes from the identity server. -Defaults to empty string. -|`server-type` |string |`@default` |Configure one of the supported types of identity servers. - -If the type does not have an explicit mapping, a warning is logged and the default implementation is used. -|`sign-jwk.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |A resource pointing to JWK with public keys of signing certificates used -to validate JWT. -|`tenants` |xref:{rootdir}/config/io_helidon_security_providers_oidc_common_TenantConfig.adoc[TenantConfig] |{nbsp} |Configurations of the tenants -|`token-endpoint-auth` |ClientAuthentication (CLIENT_SECRET_BASIC, CLIENT_SECRET_POST, CLIENT_SECRET_JWT, PRIVATE_KEY_JWT, NONE) |`CLIENT_SECRET_BASIC` |Type of authentication to use when invoking the token endpoint. -Current supported options: - -- io.helidon.security.providers.oidc.common.OidcConfig.ClientAuthentication.CLIENT_SECRET_BASIC -- io.helidon.security.providers.oidc.common.OidcConfig.ClientAuthentication.CLIENT_SECRET_POST -- io.helidon.security.providers.oidc.common.OidcConfig.ClientAuthentication.NONE - -Allowed values: - -- `CLIENT_SECRET_BASIC`: Clients that have received a client_secret value from the Authorization Server authenticate with the Authorization -Server in accordance with Section 2.3.1 of OAuth 2.0 [RFC6749] using the HTTP Basic authentication scheme. -This is the default client authentication. -- `CLIENT_SECRET_POST`: Clients that have received a client_secret value from the Authorization Server, authenticate with the Authorization -Server in accordance with Section 2.3.1 of OAuth 2.0 [RFC6749] by including the Client Credentials in the request body. -- `CLIENT_SECRET_JWT`: Clients that have received a client_secret value from the Authorization Server create a JWT using an HMAC SHA -algorithm, such as HMAC SHA-256. The HMAC (Hash-based Message Authentication Code) is calculated using the octets of -the UTF-8 representation of the client_secret as the shared key. -The Client authenticates in accordance with JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and -Authorization Grants [OAuth.JWT] and Assertion Framework for OAuth 2.0 Client Authentication and Authorization -Grants [OAuth.Assertions]. - -The JWT MUST contain the following REQUIRED Claim Values and MAY contain the following -OPTIONAL Claim Values. - -Required: -`iss, sub, aud, jti, exp` - -Optional: -`iat` -- `PRIVATE_KEY_JWT`: Clients that have registered a public key sign a JWT using that key. The Client authenticates in accordance with -JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants [OAuth.JWT] and Assertion -Framework for OAuth 2.0 Client Authentication and Authorization Grants [OAuth.Assertions]. - -The JWT MUST contain the following REQUIRED Claim Values and MAY contain the following -OPTIONAL Claim Values. - -Required: -`iss, sub, aud, jti, exp` - -Optional: -`iat` -- `NONE`: The Client does not authenticate itself at the Token Endpoint, either because it uses only the Implicit Flow (and so -does not use the Token Endpoint) or because it is a Public Client with no Client Secret or other authentication -mechanism. - -|`token-endpoint-uri` |URI |{nbsp} |URI of a token endpoint used to obtain a JWT based on the authentication -code. -If not defined, it is obtained from oidcMetadata(Resource), if that is not defined -an attempt is made to use identityUri(URI)/oauth2/v1/token. -|`token-signature-validation` |boolean |`true` |Whether access token signature check should be enabled. -Signature check is enabled by default, and it is highly recommended to not change that. -Change this setting only when you really know what you are doing, otherwise it could case security issues. -|`use-jwt-groups` |boolean |`true` |Claim `groups` from JWT will be used to automatically add - groups to current subject (may be used with jakarta.annotation.security.RolesAllowed annotation). -|`validate-jwt-with-jwk` |boolean |`true` |Use JWK (a set of keys to validate signatures of JWT) to validate tokens. -Use this method when you want to use default values for JWK or introspection endpoint URI. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_common_BaseBuilder.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_common_BaseBuilder.adoc deleted file mode 100644 index becac070edd..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_common_BaseBuilder.adoc +++ /dev/null @@ -1,132 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.security.providers.oidc.common.BaseBuilder -:keywords: helidon, config, io.helidon.security.providers.oidc.common.BaseBuilder -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.security.providers.oidc.common.BaseBuilder -include::{rootdir}/includes/attributes.adoc[] - -= BaseBuilder (security.providers.oidc.common) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.security.providers.oidc.common/io/helidon/security/providers/oidc/common/BaseBuilder.html[io.helidon.security.providers.oidc.common.BaseBuilder] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`audience` |string |{nbsp} |Audience of issued tokens. -|`authorization-endpoint-uri` |URI |{nbsp} |URI of an authorization endpoint used to redirect users to for logging-in. - -If not defined, it is obtained from oidcMetadata(Resource), if that is not defined -an attempt is made to use identityUri(URI)/oauth2/v1/authorize. -|`base-scopes` |string |`openid` |Configure base scopes. -By default, this is DEFAULT_BASE_SCOPES. -If scope has a qualifier, it must be used here. -|`check-audience` |boolean |`false` |Configure audience claim check. -|`client-id` |string |{nbsp} |Client ID as generated by OIDC server. -|`client-secret` |string |{nbsp} |Client secret as generated by OIDC server. -Used to authenticate this application with the server when requesting -JWT based on a code. -|`client-timeout-millis` |Duration |`30000` |Timeout of calls using web client. -|`identity-uri` |URI |{nbsp} |URI of the identity server, base used to retrieve OIDC metadata. -|`introspect-endpoint-uri` |URI |{nbsp} |Endpoint to use to validate JWT. -Either use this or set signJwk(JwkKeys) or signJwk(Resource). -|`issuer` |string |{nbsp} |Issuer of issued tokens. -|`oidc-metadata-well-known` |boolean |`true` |If set to true, metadata will be loaded from default (well known) -location, unless it is explicitly defined using oidc-metadata-resource. If set to false, it would not be loaded -even if oidc-metadata-resource is not defined. In such a case all URIs must be explicitly defined (e.g. -token-endpoint-uri). -|`oidc-metadata.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Resource configuration for OIDC Metadata -containing endpoints to various identity services, as well as information about the identity server. -|`optional-audience` |boolean |`false` |Allow audience claim to be optional. -|`scope-audience` |string |{nbsp} |Audience of the scope required by this application. This is prefixed to -the scope name when requesting scopes from the identity server. -Defaults to empty string. -|`server-type` |string |`@default` |Configure one of the supported types of identity servers. - -If the type does not have an explicit mapping, a warning is logged and the default implementation is used. -|`sign-jwk.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |A resource pointing to JWK with public keys of signing certificates used -to validate JWT. -|`token-endpoint-auth` |ClientAuthentication (CLIENT_SECRET_BASIC, CLIENT_SECRET_POST, CLIENT_SECRET_JWT, PRIVATE_KEY_JWT, NONE) |`CLIENT_SECRET_BASIC` |Type of authentication to use when invoking the token endpoint. -Current supported options: - -- io.helidon.security.providers.oidc.common.OidcConfig.ClientAuthentication.CLIENT_SECRET_BASIC -- io.helidon.security.providers.oidc.common.OidcConfig.ClientAuthentication.CLIENT_SECRET_POST -- io.helidon.security.providers.oidc.common.OidcConfig.ClientAuthentication.NONE - -Allowed values: - -- `CLIENT_SECRET_BASIC`: Clients that have received a client_secret value from the Authorization Server authenticate with the Authorization -Server in accordance with Section 2.3.1 of OAuth 2.0 [RFC6749] using the HTTP Basic authentication scheme. -This is the default client authentication. -- `CLIENT_SECRET_POST`: Clients that have received a client_secret value from the Authorization Server, authenticate with the Authorization -Server in accordance with Section 2.3.1 of OAuth 2.0 [RFC6749] by including the Client Credentials in the request body. -- `CLIENT_SECRET_JWT`: Clients that have received a client_secret value from the Authorization Server create a JWT using an HMAC SHA -algorithm, such as HMAC SHA-256. The HMAC (Hash-based Message Authentication Code) is calculated using the octets of -the UTF-8 representation of the client_secret as the shared key. -The Client authenticates in accordance with JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and -Authorization Grants [OAuth.JWT] and Assertion Framework for OAuth 2.0 Client Authentication and Authorization -Grants [OAuth.Assertions]. - -The JWT MUST contain the following REQUIRED Claim Values and MAY contain the following -OPTIONAL Claim Values. - -Required: -`iss, sub, aud, jti, exp` - -Optional: -`iat` -- `PRIVATE_KEY_JWT`: Clients that have registered a public key sign a JWT using that key. The Client authenticates in accordance with -JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants [OAuth.JWT] and Assertion -Framework for OAuth 2.0 Client Authentication and Authorization Grants [OAuth.Assertions]. - -The JWT MUST contain the following REQUIRED Claim Values and MAY contain the following -OPTIONAL Claim Values. - -Required: -`iss, sub, aud, jti, exp` - -Optional: -`iat` -- `NONE`: The Client does not authenticate itself at the Token Endpoint, either because it uses only the Implicit Flow (and so -does not use the Token Endpoint) or because it is a Public Client with no Client Secret or other authentication -mechanism. - -|`token-endpoint-uri` |URI |{nbsp} |URI of a token endpoint used to obtain a JWT based on the authentication -code. -If not defined, it is obtained from oidcMetadata(Resource), if that is not defined -an attempt is made to use identityUri(URI)/oauth2/v1/token. -|`validate-jwt-with-jwk` |boolean |`true` |Use JWK (a set of keys to validate signatures of JWT) to validate tokens. -Use this method when you want to use default values for JWK or introspection endpoint URI. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_common_OidcConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_common_OidcConfig.adoc deleted file mode 100644 index 17742c33dfa..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_common_OidcConfig.adoc +++ /dev/null @@ -1,231 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.security.providers.oidc.common.OidcConfig -:keywords: helidon, config, io.helidon.security.providers.oidc.common.OidcConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.security.providers.oidc.common.OidcConfig -include::{rootdir}/includes/attributes.adoc[] - -= OidcConfig (security.providers.oidc.common) Configuration - -// tag::config[] - -Open ID Connect configuration - - -Type: link:{javadoc-base-url}/io.helidon.security.providers.oidc.common/io/helidon/security/providers/oidc/common/OidcConfig.html[io.helidon.security.providers.oidc.common.OidcConfig] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`access-token-ip-check` |boolean |`true` |Whether to check if current IP address matches the one access token was issued for. -This check helps with cookie replay attack prevention. -|`audience` |string |{nbsp} |Audience of issued tokens. -|`authorization-endpoint-uri` |URI |{nbsp} |URI of an authorization endpoint used to redirect users to for logging-in. - -If not defined, it is obtained from oidcMetadata(Resource), if that is not defined -an attempt is made to use identityUri(URI)/oauth2/v1/authorize. -|`base-scopes` |string |`openid` |Configure base scopes. -By default, this is DEFAULT_BASE_SCOPES. -If scope has a qualifier, it must be used here. -|`check-audience` |boolean |`false` |Configure audience claim check. -|`client-id` |string |{nbsp} |Client ID as generated by OIDC server. -|`client-secret` |string |{nbsp} |Client secret as generated by OIDC server. -Used to authenticate this application with the server when requesting -JWT based on a code. -|`client-timeout-millis` |Duration |`30000` |Timeout of calls using web client. -|`cookie-domain` |string |{nbsp} |Domain the cookie is valid for. -Not used by default. -|`cookie-encryption-enabled` |boolean |`false` |Whether to encrypt token cookie created by this microservice. -Defaults to `false`. -|`cookie-encryption-id-enabled` |boolean |`true` |Whether to encrypt id token cookie created by this microservice. -Defaults to `true`. -|`cookie-encryption-name` |string |{nbsp} |Name of the encryption configuration available through Security.encrypt(String, byte[]) and -Security.decrypt(String, String). -If configured and encryption is enabled for any cookie, -Security MUST be configured in global or current `io.helidon.common.context.Context` (this -is done automatically in Helidon MP). -|`cookie-encryption-password` |char[] |{nbsp} |Master password for encryption/decryption of cookies. This must be configured to the same value on each microservice -using the cookie. -|`cookie-encryption-refresh-enabled` |boolean |`true` |Whether to encrypt refresh token cookie created by this microservice. -Defaults to `true`. -|`cookie-encryption-state-enabled` |boolean |`true` |Whether to encrypt state cookie created by this microservice. -Defaults to `true`. -|`cookie-encryption-tenant-enabled` |boolean |`true` |Whether to encrypt tenant name cookie created by this microservice. -Defaults to `true`. -|`cookie-http-only` |boolean |`true` |When using cookie, if set to true, the HttpOnly attribute will be configured. -Defaults to OidcCookieHandler.Builder.DEFAULT_HTTP_ONLY. -|`cookie-max-age-seconds` |long |{nbsp} |When using cookie, used to set MaxAge attribute of the cookie, defining how long -the cookie is valid. -Not used by default. -|`cookie-name` |string |`JSESSIONID` |Name of the cookie to use. -Defaults to DEFAULT_COOKIE_NAME. -|`cookie-name-id-token` |string |`JSESSIONID_2` |Name of the cookie to use for id token. -Defaults to DEFAULT_COOKIE_NAME_2. - -This cookie is only used when logout is enabled, as otherwise it is not needed. -Content of this cookie is encrypted. -|`cookie-name-refresh-token` |string |`JSESSIONID_3` |The name of the cookie to use for the refresh token. -Defaults to DEFAULT_REFRESH_COOKIE_NAME. -|`cookie-name-state` |string |`JSESSIONID_3` |The name of the cookie to use for the state storage. -Defaults to DEFAULT_STATE_COOKIE_NAME. -|`cookie-name-tenant` |string |`HELIDON_TENANT` |The name of the cookie to use for the tenant name. -Defaults to DEFAULT_TENANT_COOKIE_NAME. -|`cookie-path` |string |`/` |Path the cookie is valid for. -Defaults to "/". -|`cookie-same-site` |SameSite (LAX, STRICT, NONE) |`LAX` |When using cookie, used to set the SameSite cookie value. Can be -"Strict" or "Lax". -|`cookie-secure` |boolean |`false` |When using cookie, if set to true, the Secure attribute will be configured. -Defaults to false. -|`cookie-use` |boolean |`true` |Whether to use cookie to store JWT between requests. -Defaults to DEFAULT_COOKIE_USE. -|`cors` |xref:{rootdir}/config/io_helidon_cors_CrossOriginConfig.adoc[CrossOriginConfig] |{nbsp} |Assign cross-origin resource sharing settings. -|`force-https-redirects` |boolean |`false` |Force HTTPS for redirects to identity provider. -Defaults to `false`. -|`frontend-uri` |string |{nbsp} |Full URI of this application that is visible from user browser. -Used to redirect request back from identity server after successful login. -|`header-token` |xref:{rootdir}/config/io_helidon_security_util_TokenHandler.adoc[TokenHandler] |{nbsp} |A TokenHandler to -process header containing a JWT. -Default is "Authorization" header with a prefix "bearer ". -|`header-use` |boolean |`true` |Whether to expect JWT in a header field. -|`id-token-signature-validation` |boolean |`true` |Whether id token signature check should be enabled. -Signature check is enabled by default, and it is highly recommended to not change that. -Change this setting only when you really know what you are doing, otherwise it could case security issues. -|`identity-uri` |URI |{nbsp} |URI of the identity server, base used to retrieve OIDC metadata. -|`introspect-endpoint-uri` |URI |{nbsp} |Endpoint to use to validate JWT. -Either use this or set signJwk(JwkKeys) or signJwk(Resource). -|`issuer` |string |{nbsp} |Issuer of issued tokens. -|`max-redirects` |int |`5` |Configure maximal number of redirects when redirecting to an OIDC provider within a single authentication -attempt. - -Defaults to DEFAULT_MAX_REDIRECTS -|`oidc-metadata-well-known` |boolean |`true` |If set to true, metadata will be loaded from default (well known) -location, unless it is explicitly defined using oidc-metadata-resource. If set to false, it would not be loaded -even if oidc-metadata-resource is not defined. In such a case all URIs must be explicitly defined (e.g. -token-endpoint-uri). -|`oidc-metadata.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Resource configuration for OIDC Metadata -containing endpoints to various identity services, as well as information about the identity server. -|`optional-audience` |boolean |`false` |Allow audience claim to be optional. -|`proxy-host` |string |{nbsp} |Proxy host to use. When defined, triggers usage of proxy for HTTP requests. -Setting to empty String has the same meaning as setting to null - disables proxy. -|`proxy-port` |int |`80` |Proxy port. -Defaults to DEFAULT_PROXY_PORT -|`proxy-protocol` |string |`http` |Proxy protocol to use when proxy is used. -Defaults to DEFAULT_PROXY_PROTOCOL. -|`query-id-token-param-name` |string |`id_token` |Name of a query parameter that contains the JWT id token when parameter is used. -|`query-param-name` |string |`accessToken` |Name of a query parameter that contains the JWT access token when parameter is used. -|`query-param-tenant-name` |string |`h_tenant` |Name of a query parameter that contains the tenant name when the parameter is used. -Defaults to DEFAULT_TENANT_PARAM_NAME. -|`query-param-use` |boolean |`false` |Whether to use a query parameter to send JWT token from application to this -server. -|`redirect` |boolean |`false` |By default, the client should redirect to the identity server for the user to log in. -This behavior can be overridden by setting redirect to false. When token is not present in the request, the client -will not redirect and just return appropriate error response code. -|`redirect-attempt-param` |string |`h_ra` |Configure the parameter used to store the number of attempts in redirect. - -Defaults to DEFAULT_ATTEMPT_PARAM -|`redirect-uri` |string |`/oidc/redirect` |URI to register web server component on, used by the OIDC server to -redirect authorization requests to after a user logs in or approves -scopes. -Note that usually the redirect URI configured here must be the -same one as configured on OIDC server. - -Defaults to DEFAULT_REDIRECT_URI -|`relative-uris` |boolean |`false` |Can be set to `true` to force the use of relative URIs in all requests, -regardless of the presence or absence of proxies or no-proxy lists. By default, -requests that use the Proxy will have absolute URIs. Set this flag to `true` -if the host is unable to accept absolute URIs. -Defaults to DEFAULT_RELATIVE_URIS. -|`scope-audience` |string |{nbsp} |Audience of the scope required by this application. This is prefixed to -the scope name when requesting scopes from the identity server. -Defaults to empty string. -|`server-type` |string |`@default` |Configure one of the supported types of identity servers. - -If the type does not have an explicit mapping, a warning is logged and the default implementation is used. -|`sign-jwk.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |A resource pointing to JWK with public keys of signing certificates used -to validate JWT. -|`tenants` |xref:{rootdir}/config/io_helidon_security_providers_oidc_common_TenantConfig.adoc[TenantConfig] |{nbsp} |Configurations of the tenants -|`token-endpoint-auth` |ClientAuthentication (CLIENT_SECRET_BASIC, CLIENT_SECRET_POST, CLIENT_SECRET_JWT, PRIVATE_KEY_JWT, NONE) |`CLIENT_SECRET_BASIC` |Type of authentication to use when invoking the token endpoint. -Current supported options: - -- io.helidon.security.providers.oidc.common.OidcConfig.ClientAuthentication.CLIENT_SECRET_BASIC -- io.helidon.security.providers.oidc.common.OidcConfig.ClientAuthentication.CLIENT_SECRET_POST -- io.helidon.security.providers.oidc.common.OidcConfig.ClientAuthentication.NONE - -Allowed values: - -- `CLIENT_SECRET_BASIC`: Clients that have received a client_secret value from the Authorization Server authenticate with the Authorization -Server in accordance with Section 2.3.1 of OAuth 2.0 [RFC6749] using the HTTP Basic authentication scheme. -This is the default client authentication. -- `CLIENT_SECRET_POST`: Clients that have received a client_secret value from the Authorization Server, authenticate with the Authorization -Server in accordance with Section 2.3.1 of OAuth 2.0 [RFC6749] by including the Client Credentials in the request body. -- `CLIENT_SECRET_JWT`: Clients that have received a client_secret value from the Authorization Server create a JWT using an HMAC SHA -algorithm, such as HMAC SHA-256. The HMAC (Hash-based Message Authentication Code) is calculated using the octets of -the UTF-8 representation of the client_secret as the shared key. -The Client authenticates in accordance with JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and -Authorization Grants [OAuth.JWT] and Assertion Framework for OAuth 2.0 Client Authentication and Authorization -Grants [OAuth.Assertions]. - -The JWT MUST contain the following REQUIRED Claim Values and MAY contain the following -OPTIONAL Claim Values. - -Required: -`iss, sub, aud, jti, exp` - -Optional: -`iat` -- `PRIVATE_KEY_JWT`: Clients that have registered a public key sign a JWT using that key. The Client authenticates in accordance with -JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants [OAuth.JWT] and Assertion -Framework for OAuth 2.0 Client Authentication and Authorization Grants [OAuth.Assertions]. - -The JWT MUST contain the following REQUIRED Claim Values and MAY contain the following -OPTIONAL Claim Values. - -Required: -`iss, sub, aud, jti, exp` - -Optional: -`iat` -- `NONE`: The Client does not authenticate itself at the Token Endpoint, either because it uses only the Implicit Flow (and so -does not use the Token Endpoint) or because it is a Public Client with no Client Secret or other authentication -mechanism. - -|`token-endpoint-uri` |URI |{nbsp} |URI of a token endpoint used to obtain a JWT based on the authentication -code. -If not defined, it is obtained from oidcMetadata(Resource), if that is not defined -an attempt is made to use identityUri(URI)/oauth2/v1/token. -|`token-signature-validation` |boolean |`true` |Whether access token signature check should be enabled. -Signature check is enabled by default, and it is highly recommended to not change that. -Change this setting only when you really know what you are doing, otherwise it could case security issues. -|`validate-jwt-with-jwk` |boolean |`true` |Use JWK (a set of keys to validate signatures of JWT) to validate tokens. -Use this method when you want to use default values for JWK or introspection endpoint URI. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_common_TenantConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_common_TenantConfig.adoc deleted file mode 100644 index eb160f72a0e..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_security_providers_oidc_common_TenantConfig.adoc +++ /dev/null @@ -1,143 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.security.providers.oidc.common.TenantConfig -:keywords: helidon, config, io.helidon.security.providers.oidc.common.TenantConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.security.providers.oidc.common.TenantConfig -include::{rootdir}/includes/attributes.adoc[] - -= TenantConfig (security.providers.oidc.common) Configuration - -// tag::config[] - -Open ID Connect tenant configuration - - -Type: link:{javadoc-base-url}/io.helidon.security.providers.oidc.common/io/helidon/security/providers/oidc/common/TenantConfig.html[io.helidon.security.providers.oidc.common.TenantConfig] - - - - -== Configuration options - -.Required configuration options -[cols="3,3a,2,5a"] -|=== -|key |type |default value |description - -|`name` |string |{nbsp} |Name of the tenant. - -|=== - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`audience` |string |{nbsp} |Audience of issued tokens. -|`authorization-endpoint-uri` |URI |{nbsp} |URI of an authorization endpoint used to redirect users to for logging-in. - -If not defined, it is obtained from oidcMetadata(Resource), if that is not defined -an attempt is made to use identityUri(URI)/oauth2/v1/authorize. -|`base-scopes` |string |`openid` |Configure base scopes. -By default, this is DEFAULT_BASE_SCOPES. -If scope has a qualifier, it must be used here. -|`check-audience` |boolean |`false` |Configure audience claim check. -|`client-id` |string |{nbsp} |Client ID as generated by OIDC server. -|`client-secret` |string |{nbsp} |Client secret as generated by OIDC server. -Used to authenticate this application with the server when requesting -JWT based on a code. -|`client-timeout-millis` |Duration |`30000` |Timeout of calls using web client. -|`identity-uri` |URI |{nbsp} |URI of the identity server, base used to retrieve OIDC metadata. -|`introspect-endpoint-uri` |URI |{nbsp} |Endpoint to use to validate JWT. -Either use this or set signJwk(JwkKeys) or signJwk(Resource). -|`issuer` |string |{nbsp} |Issuer of issued tokens. -|`oidc-metadata-well-known` |boolean |`true` |If set to true, metadata will be loaded from default (well known) -location, unless it is explicitly defined using oidc-metadata-resource. If set to false, it would not be loaded -even if oidc-metadata-resource is not defined. In such a case all URIs must be explicitly defined (e.g. -token-endpoint-uri). -|`oidc-metadata.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Resource configuration for OIDC Metadata -containing endpoints to various identity services, as well as information about the identity server. -|`optional-audience` |boolean |`false` |Allow audience claim to be optional. -|`scope-audience` |string |{nbsp} |Audience of the scope required by this application. This is prefixed to -the scope name when requesting scopes from the identity server. -Defaults to empty string. -|`server-type` |string |`@default` |Configure one of the supported types of identity servers. - -If the type does not have an explicit mapping, a warning is logged and the default implementation is used. -|`sign-jwk.resource` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |A resource pointing to JWK with public keys of signing certificates used -to validate JWT. -|`token-endpoint-auth` |ClientAuthentication (CLIENT_SECRET_BASIC, CLIENT_SECRET_POST, CLIENT_SECRET_JWT, PRIVATE_KEY_JWT, NONE) |`CLIENT_SECRET_BASIC` |Type of authentication to use when invoking the token endpoint. -Current supported options: - -- io.helidon.security.providers.oidc.common.OidcConfig.ClientAuthentication.CLIENT_SECRET_BASIC -- io.helidon.security.providers.oidc.common.OidcConfig.ClientAuthentication.CLIENT_SECRET_POST -- io.helidon.security.providers.oidc.common.OidcConfig.ClientAuthentication.NONE - -Allowed values: - -- `CLIENT_SECRET_BASIC`: Clients that have received a client_secret value from the Authorization Server authenticate with the Authorization -Server in accordance with Section 2.3.1 of OAuth 2.0 [RFC6749] using the HTTP Basic authentication scheme. -This is the default client authentication. -- `CLIENT_SECRET_POST`: Clients that have received a client_secret value from the Authorization Server, authenticate with the Authorization -Server in accordance with Section 2.3.1 of OAuth 2.0 [RFC6749] by including the Client Credentials in the request body. -- `CLIENT_SECRET_JWT`: Clients that have received a client_secret value from the Authorization Server create a JWT using an HMAC SHA -algorithm, such as HMAC SHA-256. The HMAC (Hash-based Message Authentication Code) is calculated using the octets of -the UTF-8 representation of the client_secret as the shared key. -The Client authenticates in accordance with JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and -Authorization Grants [OAuth.JWT] and Assertion Framework for OAuth 2.0 Client Authentication and Authorization -Grants [OAuth.Assertions]. - -The JWT MUST contain the following REQUIRED Claim Values and MAY contain the following -OPTIONAL Claim Values. - -Required: -`iss, sub, aud, jti, exp` - -Optional: -`iat` -- `PRIVATE_KEY_JWT`: Clients that have registered a public key sign a JWT using that key. The Client authenticates in accordance with -JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants [OAuth.JWT] and Assertion -Framework for OAuth 2.0 Client Authentication and Authorization Grants [OAuth.Assertions]. - -The JWT MUST contain the following REQUIRED Claim Values and MAY contain the following -OPTIONAL Claim Values. - -Required: -`iss, sub, aud, jti, exp` - -Optional: -`iat` -- `NONE`: The Client does not authenticate itself at the Token Endpoint, either because it uses only the Implicit Flow (and so -does not use the Token Endpoint) or because it is a Public Client with no Client Secret or other authentication -mechanism. - -|`token-endpoint-uri` |URI |{nbsp} |URI of a token endpoint used to obtain a JWT based on the authentication -code. -If not defined, it is obtained from oidcMetadata(Resource), if that is not defined -an attempt is made to use identityUri(URI)/oauth2/v1/token. -|`validate-jwt-with-jwk` |boolean |`true` |Use JWK (a set of keys to validate signatures of JWT) to validate tokens. -Use this method when you want to use default values for JWK or introspection endpoint URI. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_security_util_TokenHandler.adoc b/docs/src/main/asciidoc/config/io_helidon_security_util_TokenHandler.adoc deleted file mode 100644 index 3f8c5f8b4d7..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_security_util_TokenHandler.adoc +++ /dev/null @@ -1,52 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.security.util.TokenHandler -:keywords: helidon, config, io.helidon.security.util.TokenHandler -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.security.util.TokenHandler -include::{rootdir}/includes/attributes.adoc[] - -= TokenHandler (security.util) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.security.util/io/helidon/security/util/TokenHandler.html[io.helidon.security.util.TokenHandler] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`format` |string |{nbsp} |Token format for creating outbound tokens. -|`header` |string |{nbsp} |Set the name of header to look into to extract the token. -|`prefix` |string |{nbsp} |Set the prefix of header value to extract the token. -|`regexp` |string |{nbsp} |Set the token pattern (Regular expression) to extract the token. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_tracing_Tracer.adoc b/docs/src/main/asciidoc/config/io_helidon_tracing_Tracer.adoc deleted file mode 100644 index 0ea887603a7..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_tracing_Tracer.adoc +++ /dev/null @@ -1,86 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.tracing.Tracer -:keywords: helidon, config, io.helidon.tracing.Tracer -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.tracing.Tracer -include::{rootdir}/includes/attributes.adoc[] - -= Tracer (tracing) Configuration - -// tag::config[] - -Jaeger tracer configuration. - - -Type: link:{javadoc-base-url}/io.helidon.tracing/io/helidon/tracing/Tracer.html[io.helidon.tracing.Tracer] - - -This is a standalone configuration type, prefix from configuration root: `tracing` - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`client-cert-pem` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Certificate of client in PEM format. -|`exporter-timeout` |Duration |`PT10S` |Timeout of exporter requests. -|`max-export-batch-size` |int |`512` |Maximum Export Batch Size of exporter requests. -|`max-queue-size` |int |`2048` |Maximum Queue Size of exporter requests. -|`private-key-pem` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Private key in PEM format. -|`propagation` |PropagationFormat[] (B3, B3_SINGLE, JAEGER, W3C) |`JAEGER` |Add propagation format to use. - -Allowed values: - -- `B3`: The Zipkin B3 trace context propagation format using multiple headers. -- `B3_SINGLE`: B3 trace context propagation using a single header. -- `JAEGER`: The Jaeger trace context propagation format. -- `W3C`: The W3C trace context propagation format. - -|`sampler-param` |Number |`1` |The sampler parameter (number). -|`sampler-type` |SamplerType (CONSTANT, RATIO) |`CONSTANT` |Sampler type. - -See https://www.jaegertracing.io/docs/latest/sampling/#client-sampling-configuration[Sampler types]. - -Allowed values: - -- `CONSTANT`: Constant sampler always makes the same decision for all traces. -It either samples all traces `1` or none of them `0`. -- `RATIO`: Ratio of the requests to sample, double value. - -|`schedule-delay` |Duration |`PT5S` |Schedule Delay of exporter requests. -|`span-processor-type` |SpanProcessorType (SIMPLE, BATCH) |`batch` |Span Processor type used. - -Allowed values: - -- `SIMPLE`: Simple Span Processor. -- `BATCH`: Batch Span Processor. - -|`trusted-cert-pem` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Trusted certificates in PEM format. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_tracing_TracerBuilder.adoc b/docs/src/main/asciidoc/config/io_helidon_tracing_TracerBuilder.adoc deleted file mode 100644 index b95e95111dc..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_tracing_TracerBuilder.adoc +++ /dev/null @@ -1,41 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.tracing.TracerBuilder -:keywords: helidon, config, io.helidon.tracing.TracerBuilder -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.tracing.TracerBuilder -include::{rootdir}/includes/attributes.adoc[] - -= TracerBuilder (tracing) Configuration - -// tag::config[] - -Tracer configuration. - - -Type: link:{javadoc-base-url}/io.helidon.tracing/io/helidon/tracing/TracerBuilder.html[io.helidon.tracing.TracerBuilder] - - - - -== Configuration options - - - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_tracing_providers_jaeger_JaegerTracerBuilder.adoc b/docs/src/main/asciidoc/config/io_helidon_tracing_providers_jaeger_JaegerTracerBuilder.adoc deleted file mode 100644 index 0ea887603a7..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_tracing_providers_jaeger_JaegerTracerBuilder.adoc +++ /dev/null @@ -1,86 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.tracing.Tracer -:keywords: helidon, config, io.helidon.tracing.Tracer -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.tracing.Tracer -include::{rootdir}/includes/attributes.adoc[] - -= Tracer (tracing) Configuration - -// tag::config[] - -Jaeger tracer configuration. - - -Type: link:{javadoc-base-url}/io.helidon.tracing/io/helidon/tracing/Tracer.html[io.helidon.tracing.Tracer] - - -This is a standalone configuration type, prefix from configuration root: `tracing` - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`client-cert-pem` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Certificate of client in PEM format. -|`exporter-timeout` |Duration |`PT10S` |Timeout of exporter requests. -|`max-export-batch-size` |int |`512` |Maximum Export Batch Size of exporter requests. -|`max-queue-size` |int |`2048` |Maximum Queue Size of exporter requests. -|`private-key-pem` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Private key in PEM format. -|`propagation` |PropagationFormat[] (B3, B3_SINGLE, JAEGER, W3C) |`JAEGER` |Add propagation format to use. - -Allowed values: - -- `B3`: The Zipkin B3 trace context propagation format using multiple headers. -- `B3_SINGLE`: B3 trace context propagation using a single header. -- `JAEGER`: The Jaeger trace context propagation format. -- `W3C`: The W3C trace context propagation format. - -|`sampler-param` |Number |`1` |The sampler parameter (number). -|`sampler-type` |SamplerType (CONSTANT, RATIO) |`CONSTANT` |Sampler type. - -See https://www.jaegertracing.io/docs/latest/sampling/#client-sampling-configuration[Sampler types]. - -Allowed values: - -- `CONSTANT`: Constant sampler always makes the same decision for all traces. -It either samples all traces `1` or none of them `0`. -- `RATIO`: Ratio of the requests to sample, double value. - -|`schedule-delay` |Duration |`PT5S` |Schedule Delay of exporter requests. -|`span-processor-type` |SpanProcessorType (SIMPLE, BATCH) |`batch` |Span Processor type used. - -Allowed values: - -- `SIMPLE`: Simple Span Processor. -- `BATCH`: Batch Span Processor. - -|`trusted-cert-pem` |xref:{rootdir}/config/io_helidon_common_configurable_Resource.adoc[Resource] |{nbsp} |Trusted certificates in PEM format. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_tracing_providers_opentracing_OpenTracingTracerBuilder.adoc b/docs/src/main/asciidoc/config/io_helidon_tracing_providers_opentracing_OpenTracingTracerBuilder.adoc deleted file mode 100644 index 42507efd6ed..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_tracing_providers_opentracing_OpenTracingTracerBuilder.adoc +++ /dev/null @@ -1,41 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.tracing.providers.opentracing.OpenTracingTracerBuilder -:keywords: helidon, config, io.helidon.tracing.providers.opentracing.OpenTracingTracerBuilder -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.tracing.providers.opentracing.OpenTracingTracerBuilder -include::{rootdir}/includes/attributes.adoc[] - -= OpenTracingTracerBuilder (tracing.providers.opentracing) Configuration - -// tag::config[] - -OpenTracing tracer configuration. - - -Type: link:{javadoc-base-url}/io.helidon.tracing.providers.opentracing/io/helidon/tracing/providers/opentracing/OpenTracingTracerBuilder.html[io.helidon.tracing.providers.opentracing.OpenTracingTracerBuilder] - - - - -== Configuration options - - - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_tracing_providers_zipkin_ZipkinTracerBuilder.adoc b/docs/src/main/asciidoc/config/io_helidon_tracing_providers_zipkin_ZipkinTracerBuilder.adoc deleted file mode 100644 index 42bed06586c..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_tracing_providers_zipkin_ZipkinTracerBuilder.adoc +++ /dev/null @@ -1,60 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.opentracing.Tracer -:keywords: helidon, config, io.opentracing.Tracer -:basic-table-intro: The table below lists the configuration keys that configure io.opentracing.Tracer -include::{rootdir}/includes/attributes.adoc[] - -= io.opentracing.Tracer Configuration - -// tag::config[] - -Zipkin tracer configuration - - -Type: io.opentracing.Tracer - - -This is a standalone configuration type, prefix from configuration root: `tracing` - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`api-version` |Version (V1, V2) |`V2` |Version of Zipkin API to use. -Defaults to Version.V2. - -Allowed values: - -- `V1`: Version 1. -- `V2`: Version 2. - - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webclient_api_HttpClientConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_webclient_api_HttpClientConfig.adoc deleted file mode 100644 index 2cc17d11de9..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webclient_api_HttpClientConfig.adoc +++ /dev/null @@ -1,141 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webclient.api.HttpClientConfig -:keywords: helidon, config, io.helidon.webclient.api.HttpClientConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webclient.api.HttpClientConfig -include::{rootdir}/includes/attributes.adoc[] - -= HttpClientConfig (webclient.api) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webclient.api/io/helidon/webclient/api/HttpClientConfig.html[io.helidon.webclient.api.HttpClientConfig] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`base-uri` |ClientUri |{nbsp} |Base uri used by the client in all requests. - -Base uri of the client requests -|`connect-timeout` |Duration |{nbsp} |Connect timeout. - -Connect timeout -See io.helidon.common.socket.SocketOptions.connectTimeout() -|`connection-cache-size` |int |`256` |Maximal size of the connection cache. -For most HTTP protocols, we may cache connections to various endpoints for keep alive (or stream reuse in case of HTTP/2). -This option limits the size. Setting this number lower than the "usual" number of target services will cause connections -to be closed and reopened frequently. -|`content-encoding` |xref:{rootdir}/config/io_helidon_http_encoding_ContentEncodingContext.adoc[ContentEncodingContext] |{nbsp} |Configure the listener specific io.helidon.http.encoding.ContentEncodingContext. -This method discards all previously registered ContentEncodingContext. -If no content encoding context is registered, default encoding context is used. - -Content encoding context -|`cookie-manager` |xref:{rootdir}/config/io_helidon_webclient_api_WebClientCookieManager.adoc[WebClientCookieManager] |{nbsp} |WebClient cookie manager. - -Cookie manager to use -|`default-headers` |Map<string, string> |{nbsp} |Default headers to be used in every request from configuration. - -Default headers -|`follow-redirects` |boolean |`true` |Whether to follow redirects. - -Whether to follow redirects -|`keep-alive` |boolean |`true` |Determines if connection keep alive is enabled (NOT socket keep alive, but HTTP connection keep alive, to re-use -the same connection for multiple requests). - -Keep alive for this connection -See io.helidon.common.socket.SocketOptions.socketKeepAlive() -|`max-in-memory-entity` |int |`131072` |If the entity is expected to be smaller that this number of bytes, it would be buffered in memory to optimize performance. -If bigger, streaming will be used. - -Note that for some entity types we cannot use streaming, as they are already fully in memory (String, byte[]), for such -cases, this option is ignored. Default is 128Kb. - -Maximal number of bytes to buffer in memory for supported writers -|`max-redirects` |int |`10` |Max number of followed redirects. -This is ignored if followRedirects() option is `false`. - -Max number of followed redirects -|`media-context` |xref:{rootdir}/config/io_helidon_http_media_MediaContext.adoc[MediaContext] |`create()` |Configure the listener specific io.helidon.http.media.MediaContext. -This method discards all previously registered MediaContext. -If no media context is registered, default media context is used. - -Media context -|`media-type-parser-mode` |ParserMode (STRICT, RELAXED) |`ParserMode.STRICT` |Configure media type parsing mode for HTTP `Content-Type` header. - -Media type parsing mode -|`properties` |Map<string, string> |{nbsp} |Properties configured for this client. These properties are propagated through client request, to be used by -services (and possibly for other purposes). - -Map of client properties -|`proxy` |xref:{rootdir}/config/io_helidon_webclient_api_Proxy.adoc[Proxy] |{nbsp} |Proxy configuration to be used for requests. - -Proxy to use, defaults to Proxy.noProxy() -|`read-continue-timeout` |Duration |`PT1S` |Socket 100-Continue read timeout. Default is 1 second. -This read timeout is used when 100-Continue is sent by the client, before it sends an entity. - -Read 100-Continue timeout duration -|`read-timeout` |Duration |{nbsp} |Read timeout. - -Read timeout -See io.helidon.common.socket.SocketOptions.readTimeout() -|`relative-uris` |boolean |`false` |Can be set to `true` to force the use of relative URIs in all requests, -regardless of the presence or absence of proxies or no-proxy lists. - -Relative URIs flag -|`send-expect-continue` |boolean |`true` |Whether Expect-100-Continue header is sent to verify server availability before sending an entity. - -Defaults to `true`. - - -Whether Expect:100-Continue header should be sent on streamed transfers -|`services` |io.helidon.webclient.spi.WebClientService[] (service provider interface) |{nbsp} |WebClient services. - -Services to use with this web client -|`share-connection-cache` |boolean |`true` |Whether to share connection cache between all the WebClient instances in JVM. - -True if connection cache is shared -|`socket-options` |xref:{rootdir}/config/io_helidon_common_socket_SocketOptions.adoc[SocketOptions] |{nbsp} |Socket options for connections opened by this client. -If there is a value explicitly configured on this type and on the socket options, -the one configured on this type's builder will win: - -- readTimeout() -- connectTimeout() - -Socket options -|`tls` |xref:{rootdir}/config/io_helidon_common_tls_Tls.adoc[Tls] |{nbsp} |TLS configuration for any TLS request from this client. -TLS can also be configured per request. -TLS is used when the protocol is set to `https`. - -TLS configuration to use - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webclient_api_HttpConfigBase.adoc b/docs/src/main/asciidoc/config/io_helidon_webclient_api_HttpConfigBase.adoc deleted file mode 100644 index e111041267e..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webclient_api_HttpConfigBase.adoc +++ /dev/null @@ -1,80 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webclient.api.HttpConfigBase -:keywords: helidon, config, io.helidon.webclient.api.HttpConfigBase -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webclient.api.HttpConfigBase -include::{rootdir}/includes/attributes.adoc[] - -= HttpConfigBase (webclient.api) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webclient.api/io/helidon/webclient/api/HttpConfigBase.html[io.helidon.webclient.api.HttpConfigBase] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`connect-timeout` |Duration |{nbsp} |Connect timeout. - -Connect timeout -See io.helidon.common.socket.SocketOptions.connectTimeout() -|`follow-redirects` |boolean |`true` |Whether to follow redirects. - -Whether to follow redirects -|`keep-alive` |boolean |`true` |Determines if connection keep alive is enabled (NOT socket keep alive, but HTTP connection keep alive, to re-use -the same connection for multiple requests). - -Keep alive for this connection -See io.helidon.common.socket.SocketOptions.socketKeepAlive() -|`max-redirects` |int |`10` |Max number of followed redirects. -This is ignored if followRedirects() option is `false`. - -Max number of followed redirects -|`properties` |Map<string, string> |{nbsp} |Properties configured for this client. These properties are propagated through client request, to be used by -services (and possibly for other purposes). - -Map of client properties -|`proxy` |xref:{rootdir}/config/io_helidon_webclient_api_Proxy.adoc[Proxy] |{nbsp} |Proxy configuration to be used for requests. - -Proxy to use, defaults to Proxy.noProxy() -|`read-timeout` |Duration |{nbsp} |Read timeout. - -Read timeout -See io.helidon.common.socket.SocketOptions.readTimeout() -|`tls` |xref:{rootdir}/config/io_helidon_common_tls_Tls.adoc[Tls] |{nbsp} |TLS configuration for any TLS request from this client. -TLS can also be configured per request. -TLS is used when the protocol is set to `https`. - -TLS configuration to use - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webclient_api_Proxy.adoc b/docs/src/main/asciidoc/config/io_helidon_webclient_api_Proxy.adoc deleted file mode 100644 index d475c6b29d6..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webclient_api_Proxy.adoc +++ /dev/null @@ -1,72 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webclient.api.Proxy -:keywords: helidon, config, io.helidon.webclient.api.Proxy -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webclient.api.Proxy -include::{rootdir}/includes/attributes.adoc[] - -= Proxy (webclient.api) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webclient.api/io/helidon/webclient/api/Proxy.html[io.helidon.webclient.api.Proxy] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`host` |string |{nbsp} |Sets a new host value. -|`no-proxy` |string[] |{nbsp} |Configure a host pattern that is not going through a proxy. - -Options are: - -- IP Address, such as `192.168.1.1` -- IP V6 Address, such as `[2001:db8:85a3:8d3:1319:8a2e:370:7348]` -- Hostname, such as `localhost` -- Domain name, such as `helidon.io` -- Domain name and all sub-domains, such as `.helidon.io` (leading dot) -- Combination of all options from above with a port, such as `.helidon.io:80` - - -|`password` |string |{nbsp} |Sets a new password for the proxy. -|`port` |int |{nbsp} |Sets a port value. -|`type` |ProxyType (NONE, SYSTEM, HTTP) |`HTTP` |Sets a new proxy type. - -Allowed values: - -- `NONE`: No proxy. -- `SYSTEM`: Proxy obtained from system. -- `HTTP`: HTTP proxy. - -|`username` |string |{nbsp} |Sets a new username for the proxy. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webclient_api_WebClient.adoc b/docs/src/main/asciidoc/config/io_helidon_webclient_api_WebClient.adoc deleted file mode 100644 index c629ec6c50c..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webclient_api_WebClient.adoc +++ /dev/null @@ -1,146 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webclient.api.WebClient -:keywords: helidon, config, io.helidon.webclient.api.WebClient -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webclient.api.WebClient -include::{rootdir}/includes/attributes.adoc[] - -= WebClient (webclient.api) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webclient.api/io/helidon/webclient/api/WebClient.html[io.helidon.webclient.api.WebClient] - - -This is a standalone configuration type, prefix from configuration root: `clients` - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`base-uri` |ClientUri |{nbsp} |Base uri used by the client in all requests. - -Base uri of the client requests -|`connect-timeout` |Duration |{nbsp} |Connect timeout. - -Connect timeout -See io.helidon.common.socket.SocketOptions.connectTimeout() -|`connection-cache-size` |int |`256` |Maximal size of the connection cache. -For most HTTP protocols, we may cache connections to various endpoints for keep alive (or stream reuse in case of HTTP/2). -This option limits the size. Setting this number lower than the "usual" number of target services will cause connections -to be closed and reopened frequently. -|`content-encoding` |xref:{rootdir}/config/io_helidon_http_encoding_ContentEncodingContext.adoc[ContentEncodingContext] |{nbsp} |Configure the listener specific io.helidon.http.encoding.ContentEncodingContext. -This method discards all previously registered ContentEncodingContext. -If no content encoding context is registered, default encoding context is used. - -Content encoding context -|`cookie-manager` |xref:{rootdir}/config/io_helidon_webclient_api_WebClientCookieManager.adoc[WebClientCookieManager] |{nbsp} |WebClient cookie manager. - -Cookie manager to use -|`default-headers` |Map<string, string> |{nbsp} |Default headers to be used in every request from configuration. - -Default headers -|`follow-redirects` |boolean |`true` |Whether to follow redirects. - -Whether to follow redirects -|`keep-alive` |boolean |`true` |Determines if connection keep alive is enabled (NOT socket keep alive, but HTTP connection keep alive, to re-use -the same connection for multiple requests). - -Keep alive for this connection -See io.helidon.common.socket.SocketOptions.socketKeepAlive() -|`max-in-memory-entity` |int |`131072` |If the entity is expected to be smaller that this number of bytes, it would be buffered in memory to optimize performance. -If bigger, streaming will be used. - -Note that for some entity types we cannot use streaming, as they are already fully in memory (String, byte[]), for such -cases, this option is ignored. Default is 128Kb. - -Maximal number of bytes to buffer in memory for supported writers -|`max-redirects` |int |`10` |Max number of followed redirects. -This is ignored if followRedirects() option is `false`. - -Max number of followed redirects -|`media-context` |xref:{rootdir}/config/io_helidon_http_media_MediaContext.adoc[MediaContext] |`create()` |Configure the listener specific io.helidon.http.media.MediaContext. -This method discards all previously registered MediaContext. -If no media context is registered, default media context is used. - -Media context -|`media-type-parser-mode` |ParserMode (STRICT, RELAXED) |`ParserMode.STRICT` |Configure media type parsing mode for HTTP `Content-Type` header. - -Media type parsing mode -|`properties` |Map<string, string> |{nbsp} |Properties configured for this client. These properties are propagated through client request, to be used by -services (and possibly for other purposes). - -Map of client properties -|`protocol-configs` |io.helidon.webclient.spi.ProtocolConfig[] (service provider interface) |{nbsp} |Configuration of client protocols. - -Client protocol configurations -|`proxy` |xref:{rootdir}/config/io_helidon_webclient_api_Proxy.adoc[Proxy] |{nbsp} |Proxy configuration to be used for requests. - -Proxy to use, defaults to Proxy.noProxy() -|`read-continue-timeout` |Duration |`PT1S` |Socket 100-Continue read timeout. Default is 1 second. -This read timeout is used when 100-Continue is sent by the client, before it sends an entity. - -Read 100-Continue timeout duration -|`read-timeout` |Duration |{nbsp} |Read timeout. - -Read timeout -See io.helidon.common.socket.SocketOptions.readTimeout() -|`relative-uris` |boolean |`false` |Can be set to `true` to force the use of relative URIs in all requests, -regardless of the presence or absence of proxies or no-proxy lists. - -Relative URIs flag -|`send-expect-continue` |boolean |`true` |Whether Expect-100-Continue header is sent to verify server availability before sending an entity. - -Defaults to `true`. - - -Whether Expect:100-Continue header should be sent on streamed transfers -|`services` |io.helidon.webclient.spi.WebClientService[] (service provider interface) |{nbsp} |WebClient services. - -Services to use with this web client -|`share-connection-cache` |boolean |`true` |Whether to share connection cache between all the WebClient instances in JVM. - -True if connection cache is shared -|`socket-options` |xref:{rootdir}/config/io_helidon_common_socket_SocketOptions.adoc[SocketOptions] |{nbsp} |Socket options for connections opened by this client. -If there is a value explicitly configured on this type and on the socket options, -the one configured on this type's builder will win: - -- readTimeout() -- connectTimeout() - -Socket options -|`tls` |xref:{rootdir}/config/io_helidon_common_tls_Tls.adoc[Tls] |{nbsp} |TLS configuration for any TLS request from this client. -TLS can also be configured per request. -TLS is used when the protocol is set to `https`. - -TLS configuration to use - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webclient_api_WebClientCookieManager.adoc b/docs/src/main/asciidoc/config/io_helidon_webclient_api_WebClientCookieManager.adoc deleted file mode 100644 index 7e5c19093f2..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webclient_api_WebClientCookieManager.adoc +++ /dev/null @@ -1,57 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webclient.api.WebClientCookieManager -:keywords: helidon, config, io.helidon.webclient.api.WebClientCookieManager -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webclient.api.WebClientCookieManager -include::{rootdir}/includes/attributes.adoc[] - -= WebClientCookieManager (webclient.api) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webclient.api/io/helidon/webclient/api/WebClientCookieManager.html[io.helidon.webclient.api.WebClientCookieManager] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`automatic-store-enabled` |boolean |`false` |Whether automatic cookie store is enabled or not. - -Status of cookie store -|`cookie-policy` |CookiePolicy |`java.net.CookiePolicy.ACCEPT_ORIGINAL_SERVER` |Current cookie policy for this client. - -The cookie policy -|`default-cookies` |Map<string, string> |{nbsp} |Map of default cookies to include in all requests if cookies enabled. - -Map of default cookies - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webclient_grpc_GrpcClient.adoc b/docs/src/main/asciidoc/config/io_helidon_webclient_grpc_GrpcClient.adoc deleted file mode 100644 index f02664d8442..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webclient_grpc_GrpcClient.adoc +++ /dev/null @@ -1,51 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webclient.grpc.GrpcClient -:keywords: helidon, config, io.helidon.webclient.grpc.GrpcClient -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webclient.grpc.GrpcClient -include::{rootdir}/includes/attributes.adoc[] - -= GrpcClient (webclient.grpc) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webclient.grpc/io/helidon/webclient/grpc/GrpcClient.html[io.helidon.webclient.grpc.GrpcClient] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`protocol-config` |xref:{rootdir}/config/io_helidon_webclient_grpc_GrpcClientProtocolConfig.adoc[GrpcClientProtocolConfig] |`create()` |gRPC specific configuration. - -Protocol specific configuration - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webclient_grpc_GrpcClientProtocolConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_webclient_grpc_GrpcClientProtocolConfig.adoc deleted file mode 100644 index 00a6250c879..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webclient_grpc_GrpcClientProtocolConfig.adoc +++ /dev/null @@ -1,71 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webclient.grpc.GrpcClientProtocolConfig -:keywords: helidon, config, io.helidon.webclient.grpc.GrpcClientProtocolConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webclient.grpc.GrpcClientProtocolConfig -include::{rootdir}/includes/attributes.adoc[] - -= GrpcClientProtocolConfig (webclient.grpc) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webclient.grpc/io/helidon/webclient/grpc/GrpcClientProtocolConfig.html[io.helidon.webclient.grpc.GrpcClientProtocolConfig] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`abort-poll-time-expired` |boolean |`false` |Whether to continue retrying after a poll wait timeout expired or not. If a read -operation timeouts out and this flag is set to `false`, the event is logged -and the client will retry. Otherwise, an exception is thrown. - -Abort timeout flag -|`heartbeat-period` |Duration |`PT0S` |How often to send a heartbeat (HTTP/2 ping) to check if the connection is still -alive. This is useful for long-running, streaming gRPC calls. It is turned off by -default but can be enabled by setting the period to a value greater than 0. - -Heartbeat period -|`init-buffer-size` |int |`2048` |Initial buffer size used to serialize gRPC request payloads. Buffers shall grow -according to the payload size, but setting this initial buffer size to a larger value -may improve performance for certain applications. - -Initial buffer size -|`name` |string |`grpc` |Name identifying this client protocol. Defaults to type. - -Name of client protocol -|`poll-wait-time` |Duration |`PT10S` |How long to wait for the next HTTP/2 data frame to arrive in underlying stream. -Whether this is a fatal error or not is controlled by abortPollTimeExpired(). - -Poll time as a duration -See io.helidon.common.socket.SocketOptions.readTimeout() - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webclient_http1_Http1ClientProtocolConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_webclient_http1_Http1ClientProtocolConfig.adoc deleted file mode 100644 index e83a2cb8eeb..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webclient_http1_Http1ClientProtocolConfig.adoc +++ /dev/null @@ -1,71 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webclient.http1.Http1ClientProtocolConfig -:keywords: helidon, config, io.helidon.webclient.http1.Http1ClientProtocolConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webclient.http1.Http1ClientProtocolConfig -include::{rootdir}/includes/attributes.adoc[] - -= Http1ClientProtocolConfig (webclient.http1) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webclient.http1/io/helidon/webclient/http1/Http1ClientProtocolConfig.html[io.helidon.webclient.http1.Http1ClientProtocolConfig] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`default-keep-alive` |boolean |`true` |Whether to use keep alive by default. - -`true` for keeping connections alive and re-using them for multiple requests (default), `false` - to create a new connection for each request -|`max-header-size` |int |`16384` |Configure the maximum allowed header size of the response. - -Maximum header size -|`max-status-line-length` |int |`256` |Configure the maximum allowed length of the status line from the response. - -Maximum status line length -|`name` |string |`http_1_1` | -|`validate-request-headers` |boolean |`false` |Sets whether the request header format is validated or not. - - Defaults to `false` as user has control on the header creation. - - -Whether request header validation should be enabled -|`validate-response-headers` |boolean |`true` |Sets whether the response header format is validated or not. - - Defaults to `true`. - - -Whether response header validation should be enabled - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webclient_http2_Http2ClientProtocolConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_webclient_http2_Http2ClientProtocolConfig.adoc deleted file mode 100644 index a5f7112df8b..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webclient_http2_Http2ClientProtocolConfig.adoc +++ /dev/null @@ -1,93 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webclient.http2.Http2ClientProtocolConfig -:keywords: helidon, config, io.helidon.webclient.http2.Http2ClientProtocolConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webclient.http2.Http2ClientProtocolConfig -include::{rootdir}/includes/attributes.adoc[] - -= Http2ClientProtocolConfig (webclient.http2) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webclient.http2/io/helidon/webclient/http2/Http2ClientProtocolConfig.html[io.helidon.webclient.http2.Http2ClientProtocolConfig] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`flow-control-block-timeout` |Duration |`PT0.1S` |Timeout for blocking between windows size check iterations. - -Timeout -|`initial-window-size` |int |`65535` |Configure INITIAL_WINDOW_SIZE setting for new HTTP/2 connections. -Sends to the server the size of the largest frame payload client is willing to receive. -Defaults to io.helidon.http.http2.WindowSize.DEFAULT_WIN_SIZE. - -Units of octets -|`max-frame-size` |int |`16384` |Configure initial MAX_FRAME_SIZE setting for new HTTP/2 connections. -Maximum size of data frames in bytes the client is prepared to accept from the server. -Default value is 2^14(16_384). - -Data frame size in bytes between 2^14(16_384) and 2^24-1(16_777_215) -|`max-header-list-size` |long |`-1` |Configure initial MAX_HEADER_LIST_SIZE setting for new HTTP/2 connections. -Sends to the server the maximum header field section size client is prepared to accept. -Defaults to `-1`, which means "unconfigured". - -Units of octets -|`name` |string |`h2` | -|`ping` |boolean |`false` |Check healthiness of cached connections with HTTP/2.0 ping frame. -Defaults to `false`. - -Use ping if true -|`ping-timeout` |Duration |`PT0.5S` |Timeout for ping probe used for checking healthiness of cached connections. -Defaults to `PT0.5S`, which means 500 milliseconds. - -Timeout -|`prior-knowledge` |boolean |`false` |Prior knowledge of HTTP/2 capabilities of the server. If server we are connecting to does not -support HTTP/2 and prior knowledge is set to `false`, only features supported by HTTP/1 will be available -and attempts to use HTTP/2 specific will throw an UnsupportedOperationException. - -[.underline]#Plain text connection# - -If prior knowledge is set to `true`, we will not attempt an upgrade of connection and use prior knowledge. -If prior knowledge is set to `false`, we will initiate an HTTP/1 connection and upgrade it to HTTP/2, -if supported by the server. -plaintext connection (`h2c`). - -[.underline]#TLS protected connection# - -If prior knowledge is set to `true`, we will negotiate protocol using HTTP/2 only, failing if not supported. -if prior knowledge is set to `false`, we will negotiate protocol using both HTTP/2 and HTTP/1, using the protocol -supported by server. - -Whether to use prior knowledge of HTTP/2 - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webclient_websocket_WsClient.adoc b/docs/src/main/asciidoc/config/io_helidon_webclient_websocket_WsClient.adoc deleted file mode 100644 index d6a01499062..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webclient_websocket_WsClient.adoc +++ /dev/null @@ -1,51 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webclient.websocket.WsClient -:keywords: helidon, config, io.helidon.webclient.websocket.WsClient -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webclient.websocket.WsClient -include::{rootdir}/includes/attributes.adoc[] - -= WsClient (webclient.websocket) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webclient.websocket/io/helidon/webclient/websocket/WsClient.html[io.helidon.webclient.websocket.WsClient] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`protocol-config` |xref:{rootdir}/config/io_helidon_webclient_websocket_WsClientProtocolConfig.adoc[WsClientProtocolConfig] |`create()` |WebSocket specific configuration. - -Protocol specific configuration - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webclient_websocket_WsClientProtocolConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_webclient_websocket_WsClientProtocolConfig.adoc deleted file mode 100644 index 2008239427a..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webclient_websocket_WsClientProtocolConfig.adoc +++ /dev/null @@ -1,50 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webclient.websocket.WsClientProtocolConfig -:keywords: helidon, config, io.helidon.webclient.websocket.WsClientProtocolConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webclient.websocket.WsClientProtocolConfig -include::{rootdir}/includes/attributes.adoc[] - -= WsClientProtocolConfig (webclient.websocket) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webclient.websocket/io/helidon/webclient/websocket/WsClientProtocolConfig.html[io.helidon.webclient.websocket.WsClientProtocolConfig] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`name` |string |`websocket` | -|`sub-protocols` |string[] |{nbsp} | - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_ConnectionConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_ConnectionConfig.adoc deleted file mode 100644 index 1f61d668819..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_ConnectionConfig.adoc +++ /dev/null @@ -1,83 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.ConnectionConfig -:keywords: helidon, config, io.helidon.webserver.ConnectionConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.ConnectionConfig -include::{rootdir}/includes/attributes.adoc[] - -= ConnectionConfig (webserver) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webserver/io/helidon/webserver/ConnectionConfig.html[io.helidon.webserver.ConnectionConfig] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`connect-timeout` |Duration |`PT10S` |Connect timeout. -Default is DEFAULT_CONNECT_TIMEOUT_DURATION. - -Connect timeout -|`keep-alive` |boolean |`true` |Configure socket keep alive. -Default is `true`. - -Keep alive -See java.net.StandardSocketOptions.SO_KEEPALIVE -|`read-timeout` |Duration |`PT30S` |Read timeout. -Default is DEFAULT_READ_TIMEOUT_DURATION - -Read timeout -|`receive-buffer-size` |int |`32768` |Socket receive buffer size. -Default is DEFAULT_SO_BUFFER_SIZE. - -Buffer size, in bytes -See java.net.StandardSocketOptions.SO_RCVBUF -|`reuse-address` |boolean |`true` |Socket reuse address. -Default is `true`. - -Whether to reuse address -See java.net.StandardSocketOptions.SO_REUSEADDR -|`send-buffer-size` |int |`32768` |Socket send buffer size. -Default is DEFAULT_SO_BUFFER_SIZE. - -Buffer size, in bytes -See java.net.StandardSocketOptions.SO_SNDBUF -|`tcp-no-delay` |boolean |`false` |Disable https://en.wikipedia.org/wiki/Nagle%27s_algorithm[Nagle's algorithm] by setting -TCP_NODELAY to true. This can result in better performance on Mac or newer linux kernels for some -payload types. -Default is `false`. - -Whether to use TCP_NODELAY, defaults to `false` -See java.net.StandardSocketOptions.TCP_NODELAY - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_ListenerConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_ListenerConfig.adoc deleted file mode 100644 index d491bf59fa4..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_ListenerConfig.adoc +++ /dev/null @@ -1,165 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.ListenerConfig -:keywords: helidon, config, io.helidon.webserver.ListenerConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.ListenerConfig -include::{rootdir}/includes/attributes.adoc[] - -= ListenerConfig (webserver) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webserver/io/helidon/webserver/ListenerConfig.html[io.helidon.webserver.ListenerConfig] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`backlog` |int |`1024` |Accept backlog. - -Backlog -|`connection-config` |xref:{rootdir}/config/io_helidon_webserver_ConnectionConfig.adoc[ConnectionConfig] |{nbsp} |Configuration of a connection (established from client against our server). - -Connection configuration -|`connection-options` |xref:{rootdir}/config/io_helidon_common_socket_SocketOptions.adoc[SocketOptions] |{nbsp} |Options for connections accepted by this listener. -This is not used to setup server connection. - -Socket options -|`content-encoding` |xref:{rootdir}/config/io_helidon_http_encoding_ContentEncodingContext.adoc[ContentEncodingContext] |{nbsp} |Configure the listener specific io.helidon.http.encoding.ContentEncodingContext. -This method discards all previously registered ContentEncodingContext. -If no content encoding context is registered, content encoding context of the webserver would be used. - -Content encoding context -|`host` |string |`0.0.0.0` |Host of the default socket. Defaults to all host addresses (`0.0.0.0`). - -Host address to listen on (for the default socket) -|`idle-connection-period` |Duration |`PT2M` |How often should we check for idleConnectionTimeout(). -Defaults to `PT2M` (2 minutes). - -Period of checking for idle connections -|`idle-connection-timeout` |Duration |`PT5M` |How long should we wait before closing a connection that has no traffic on it. -Defaults to `PT5M` (5 minutes). Note that the timestamp is refreshed max. once per second, so this setting -would be useless if configured for shorter periods of time (also not a very good support for connection keep alive, -if the connections are killed so soon anyway). - -Timeout of idle connections -|`max-concurrent-requests` |int |`-1` |Limits the number of requests that can be executed at the same time (the number of active virtual threads of requests). -Defaults to `-1`, meaning "unlimited" - what the system allows. -Also make sure that this number is higher than the expected time it takes to handle a single request in your application, -as otherwise you may stop in-progress requests. - -Number of requests that can be processed on this listener, regardless of protocol -|`max-in-memory-entity` |int |`131072` |If the entity is expected to be smaller that this number of bytes, it would be buffered in memory to optimize -performance when writing it. -If bigger, streaming will be used. - -Note that for some entity types we cannot use streaming, as they are already fully in memory (String, byte[]), for such -cases, this option is ignored. - -Default is 128Kb. - -Maximal number of bytes to buffer in memory for supported writers -|`max-payload-size` |long |`-1` |Maximal number of bytes an entity may have. -If io.helidon.http.HeaderNames.CONTENT_LENGTH is used, this is checked immediately, -if io.helidon.http.HeaderValues.TRANSFER_ENCODING_CHUNKED is used, we will fail when the -number of bytes read would exceed the max payload size. -Defaults to unlimited (`-1`). - -Maximal number of bytes of entity -|`max-tcp-connections` |int |`-1` |Limits the number of connections that can be opened at a single point in time. -Defaults to `-1`, meaning "unlimited" - what the system allows. - -Number of TCP connections that can be opened to this listener, regardless of protocol -|`media-context` |xref:{rootdir}/config/io_helidon_http_media_MediaContext.adoc[MediaContext] |{nbsp} |Configure the listener specific io.helidon.http.media.MediaContext. -This method discards all previously registered MediaContext. -If no media context is registered, media context of the webserver would be used. - -Media context -|`name` |string |`@default` |Name of this socket. Defaults to `@default`. -Must be defined if more than one socket is needed. - -Name of the socket -|`port` |int |`0` |Port of the default socket. -If configured to `0` (the default), server starts on a random port. - -Port to listen on (for the default socket) -|`protocols` |io.helidon.webserver.spi.ProtocolConfig[] (service provider interface) - -Such as: - - - xref:{rootdir}/config/io_helidon_webserver_http2_Http2Config.adoc[http_2 (Http2Config)] - - xref:{rootdir}/config/io_helidon_webserver_grpc_GrpcConfig.adoc[grpc (GrpcConfig)] - - xref:{rootdir}/config/io_helidon_webserver_websocket_WsConfig.adoc[websocket (WsConfig)] - - xref:{rootdir}/config/io_helidon_webserver_http1_Http1Config.adoc[http_1_1 (Http1Config)] - - |{nbsp} |Configuration of protocols. This may be either protocol selectors, or protocol upgraders from HTTP/1.1. -As the order is not important (providers are ordered by weight by default), we can use a configuration as an object, -such as: - ----- - -protocols: - providers: - http_1_1: - max-prologue-length: 8192 - http_2: - max-frame-size: 4096 - websocket: - .... - ----- - - -All defined protocol configurations, loaded from service loader by default -|`receive-buffer-size` |int |{nbsp} |Listener receive buffer size. - -Buffer size in bytes -|`requested-uri-discovery` |xref:{rootdir}/config/io_helidon_http_RequestedUriDiscoveryContext.adoc[RequestedUriDiscoveryContext] |{nbsp} |Requested URI discovery context. - -Discovery context -|`shutdown-grace-period` |Duration |`PT0.5S` |Grace period in ISO 8601 duration format to allow running tasks to complete before listener's shutdown. -Default is `500` milliseconds. -Configuration file values example: `PT0.5S`, `PT2S`. - -Grace period -|`tls` |xref:{rootdir}/config/io_helidon_common_tls_Tls.adoc[Tls] |{nbsp} |Listener TLS configuration. - -Tls of this configuration -|`write-buffer-size` |int |`512` |Initial buffer size in bytes of java.io.BufferedOutputStream created internally to -write data to a socket connection. Default is `512`. - -Initial buffer size used for writing -|`write-queue-length` |int |`0` |Number of buffers queued for write operations. - -Maximal number of queued writes, defaults to 0 - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_WebServer.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_WebServer.adoc deleted file mode 100644 index 1053294af48..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_WebServer.adoc +++ /dev/null @@ -1,191 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.WebServer -:keywords: helidon, config, io.helidon.webserver.WebServer -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.WebServer -include::{rootdir}/includes/attributes.adoc[] - -= WebServer (webserver) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webserver/io/helidon/webserver/WebServer.html[io.helidon.webserver.WebServer] - - -This is a standalone configuration type, prefix from configuration root: `server` - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`backlog` |int |`1024` |Accept backlog. - -Backlog -|`connection-config` |xref:{rootdir}/config/io_helidon_webserver_ConnectionConfig.adoc[ConnectionConfig] |{nbsp} |Configuration of a connection (established from client against our server). - -Connection configuration -|`connection-options` |xref:{rootdir}/config/io_helidon_common_socket_SocketOptions.adoc[SocketOptions] |{nbsp} |Options for connections accepted by this listener. -This is not used to setup server connection. - -Socket options -|`content-encoding` |xref:{rootdir}/config/io_helidon_http_encoding_ContentEncodingContext.adoc[ContentEncodingContext] |{nbsp} |Configure the listener specific io.helidon.http.encoding.ContentEncodingContext. -This method discards all previously registered ContentEncodingContext. -If no content encoding context is registered, content encoding context of the webserver would be used. - -Content encoding context -|`features` |io.helidon.webserver.spi.ServerFeature[] (service provider interface) - -Such as: - - - xref:{rootdir}/config/io_helidon_webserver_observe_ObserveFeature.adoc[observe (ObserveFeature)] - - xref:{rootdir}/config/io_helidon_webserver_context_ContextFeature.adoc[context (ContextFeature)] - - xref:{rootdir}/config/io_helidon_openapi_OpenApiFeature.adoc[openapi (OpenApiFeature)] - - xref:{rootdir}/config/io_helidon_webserver_cors_CorsFeature.adoc[cors (CorsFeature)] - - xref:{rootdir}/config/io_helidon_webserver_security_SecurityFeature.adoc[security (SecurityFeature)] - - xref:{rootdir}/config/io_helidon_webserver_accesslog_AccessLogFeature.adoc[access-log (AccessLogFeature)] - - |{nbsp} |Server features allow customization of the server, listeners, or routings. - -Server features -|`host` |string |`0.0.0.0` |Host of the default socket. Defaults to all host addresses (`0.0.0.0`). - -Host address to listen on (for the default socket) -|`idle-connection-period` |Duration |`PT2M` |How often should we check for idleConnectionTimeout(). -Defaults to `PT2M` (2 minutes). - -Period of checking for idle connections -|`idle-connection-timeout` |Duration |`PT5M` |How long should we wait before closing a connection that has no traffic on it. -Defaults to `PT5M` (5 minutes). Note that the timestamp is refreshed max. once per second, so this setting -would be useless if configured for shorter periods of time (also not a very good support for connection keep alive, -if the connections are killed so soon anyway). - -Timeout of idle connections -|`max-concurrent-requests` |int |`-1` |Limits the number of requests that can be executed at the same time (the number of active virtual threads of requests). -Defaults to `-1`, meaning "unlimited" - what the system allows. -Also make sure that this number is higher than the expected time it takes to handle a single request in your application, -as otherwise you may stop in-progress requests. - -Number of requests that can be processed on this listener, regardless of protocol -|`max-in-memory-entity` |int |`131072` |If the entity is expected to be smaller that this number of bytes, it would be buffered in memory to optimize -performance when writing it. -If bigger, streaming will be used. - -Note that for some entity types we cannot use streaming, as they are already fully in memory (String, byte[]), for such -cases, this option is ignored. - -Default is 128Kb. - -Maximal number of bytes to buffer in memory for supported writers -|`max-payload-size` |long |`-1` |Maximal number of bytes an entity may have. -If io.helidon.http.HeaderNames.CONTENT_LENGTH is used, this is checked immediately, -if io.helidon.http.HeaderValues.TRANSFER_ENCODING_CHUNKED is used, we will fail when the -number of bytes read would exceed the max payload size. -Defaults to unlimited (`-1`). - -Maximal number of bytes of entity -|`max-tcp-connections` |int |`-1` |Limits the number of connections that can be opened at a single point in time. -Defaults to `-1`, meaning "unlimited" - what the system allows. - -Number of TCP connections that can be opened to this listener, regardless of protocol -|`media-context` |xref:{rootdir}/config/io_helidon_http_media_MediaContext.adoc[MediaContext] |{nbsp} |Configure the listener specific io.helidon.http.media.MediaContext. -This method discards all previously registered MediaContext. -If no media context is registered, media context of the webserver would be used. - -Media context -|`name` |string |`@default` |Name of this socket. Defaults to `@default`. -Must be defined if more than one socket is needed. - -Name of the socket -|`port` |int |`0` |Port of the default socket. -If configured to `0` (the default), server starts on a random port. - -Port to listen on (for the default socket) -|`protocols` |io.helidon.webserver.spi.ProtocolConfig[] (service provider interface) - -Such as: - - - xref:{rootdir}/config/io_helidon_webserver_http2_Http2Config.adoc[http_2 (Http2Config)] - - xref:{rootdir}/config/io_helidon_webserver_grpc_GrpcConfig.adoc[grpc (GrpcConfig)] - - xref:{rootdir}/config/io_helidon_webserver_websocket_WsConfig.adoc[websocket (WsConfig)] - - xref:{rootdir}/config/io_helidon_webserver_http1_Http1Config.adoc[http_1_1 (Http1Config)] - - |{nbsp} |Configuration of protocols. This may be either protocol selectors, or protocol upgraders from HTTP/1.1. -As the order is not important (providers are ordered by weight by default), we can use a configuration as an object, -such as: - ----- - -protocols: - providers: - http_1_1: - max-prologue-length: 8192 - http_2: - max-frame-size: 4096 - websocket: - .... - ----- - - -All defined protocol configurations, loaded from service loader by default -|`receive-buffer-size` |int |{nbsp} |Listener receive buffer size. - -Buffer size in bytes -|`requested-uri-discovery` |xref:{rootdir}/config/io_helidon_http_RequestedUriDiscoveryContext.adoc[RequestedUriDiscoveryContext] |{nbsp} |Requested URI discovery context. - -Discovery context -|`shutdown-grace-period` |Duration |`PT0.5S` |Grace period in ISO 8601 duration format to allow running tasks to complete before listener's shutdown. -Default is `500` milliseconds. -Configuration file values example: `PT0.5S`, `PT2S`. - -Grace period -|`shutdown-hook` |boolean |`true` |When true the webserver registers a shutdown hook with the JVM Runtime. - -Defaults to true. Set this to false such that a shutdown hook is not registered. - -Whether to register a shutdown hook -|`sockets` |xref:{rootdir}/config/io_helidon_webserver_ListenerConfig.adoc[Map<string, ListenerConfig>] |{nbsp} |Socket configurations. -Note that socket named WebServer.DEFAULT_SOCKET_NAME cannot be used, -configure the values on the server directly. - -Map of listener configurations, except for the default one -|`tls` |xref:{rootdir}/config/io_helidon_common_tls_Tls.adoc[Tls] |{nbsp} |Listener TLS configuration. - -Tls of this configuration -|`write-buffer-size` |int |`512` |Initial buffer size in bytes of java.io.BufferedOutputStream created internally to -write data to a socket connection. Default is `512`. - -Initial buffer size used for writing -|`write-queue-length` |int |`0` |Number of buffers queued for write operations. - -Maximal number of queued writes, defaults to 0 - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_accesslog_AccessLogConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_accesslog_AccessLogConfig.adoc deleted file mode 100644 index 20f7eac049f..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_accesslog_AccessLogConfig.adoc +++ /dev/null @@ -1,133 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.accesslog.AccessLogFeature -:keywords: helidon, config, io.helidon.webserver.accesslog.AccessLogFeature -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.accesslog.AccessLogFeature -include::{rootdir}/includes/attributes.adoc[] - -= AccessLogFeature (webserver.accesslog) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webserver.accesslog/io/helidon/webserver/accesslog/AccessLogFeature.html[io.helidon.webserver.accesslog.AccessLogFeature] - - -[source,text] -.Config key ----- -access-log ----- - - -This type provides the following service implementations: - -- `io.helidon.webserver.spi.ServerFeatureProvider` - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`enabled` |boolean |`true` |Whether this feature will be enabled. - -Whether enabled -|`format` |string |{nbsp} |The format for log entries (similar to the Apache `LogFormat`). - -++++ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        Log format elements
        %hIP address of the remote hostHostLogEntry
        %lThe client identity. This is always undefined in Helidon.UserIdLogEntry
        %uUser ID as asserted by Helidon Security.UserLogEntry
        %tThe timestampTimestampLogEntry
        %rThe request line (`"GET /favicon.ico HTTP/1.0"`)RequestLineLogEntry
        %sThe status code returned to the clientStatusLogEntry
        %bThe entity size in bytesSizeLogEntry
        %DThe time taken in microseconds (start of request until last byte written)TimeTakenLogEntry
        %TThe time taken in seconds (start of request until last byte written), integerTimeTakenLogEntry
        %{header-name}iValue of header `header-name`HeaderLogEntry
        -++++ - - -Format string, such as `%h %l %u %t %r %b %{Referer`i} -|`logger-name` |string |`io.helidon.webserver.AccessLog` |Name of the logger used to obtain access log logger from System.getLogger(String). -Defaults to AccessLogFeature.DEFAULT_LOGGER_NAME. - -Name of the logger to use -|`sockets` |string[] |{nbsp} |List of sockets to register this feature on. If empty, it would get registered on all sockets. -The logger used will have the expected logger with a suffix of the socket name. - -Socket names to register on, defaults to empty (all available sockets) -|`weight` |double |`1000.0` |Weight of the access log feature. We need to log access for anything happening on the server, so weight is high: -io.helidon.webserver.accesslog.AccessLogFeature.WEIGHT. - -Weight of the feature - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_accesslog_AccessLogFeature.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_accesslog_AccessLogFeature.adoc deleted file mode 100644 index 20f7eac049f..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_accesslog_AccessLogFeature.adoc +++ /dev/null @@ -1,133 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.accesslog.AccessLogFeature -:keywords: helidon, config, io.helidon.webserver.accesslog.AccessLogFeature -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.accesslog.AccessLogFeature -include::{rootdir}/includes/attributes.adoc[] - -= AccessLogFeature (webserver.accesslog) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webserver.accesslog/io/helidon/webserver/accesslog/AccessLogFeature.html[io.helidon.webserver.accesslog.AccessLogFeature] - - -[source,text] -.Config key ----- -access-log ----- - - -This type provides the following service implementations: - -- `io.helidon.webserver.spi.ServerFeatureProvider` - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`enabled` |boolean |`true` |Whether this feature will be enabled. - -Whether enabled -|`format` |string |{nbsp} |The format for log entries (similar to the Apache `LogFormat`). - -++++ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        Log format elements
        %hIP address of the remote hostHostLogEntry
        %lThe client identity. This is always undefined in Helidon.UserIdLogEntry
        %uUser ID as asserted by Helidon Security.UserLogEntry
        %tThe timestampTimestampLogEntry
        %rThe request line (`"GET /favicon.ico HTTP/1.0"`)RequestLineLogEntry
        %sThe status code returned to the clientStatusLogEntry
        %bThe entity size in bytesSizeLogEntry
        %DThe time taken in microseconds (start of request until last byte written)TimeTakenLogEntry
        %TThe time taken in seconds (start of request until last byte written), integerTimeTakenLogEntry
        %{header-name}iValue of header `header-name`HeaderLogEntry
        -++++ - - -Format string, such as `%h %l %u %t %r %b %{Referer`i} -|`logger-name` |string |`io.helidon.webserver.AccessLog` |Name of the logger used to obtain access log logger from System.getLogger(String). -Defaults to AccessLogFeature.DEFAULT_LOGGER_NAME. - -Name of the logger to use -|`sockets` |string[] |{nbsp} |List of sockets to register this feature on. If empty, it would get registered on all sockets. -The logger used will have the expected logger with a suffix of the socket name. - -Socket names to register on, defaults to empty (all available sockets) -|`weight` |double |`1000.0` |Weight of the access log feature. We need to log access for anything happening on the server, so weight is high: -io.helidon.webserver.accesslog.AccessLogFeature.WEIGHT. - -Weight of the feature - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_context_ContextFeature.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_context_ContextFeature.adoc deleted file mode 100644 index 9af38b286ed..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_context_ContextFeature.adoc +++ /dev/null @@ -1,65 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.context.ContextFeature -:keywords: helidon, config, io.helidon.webserver.context.ContextFeature -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.context.ContextFeature -include::{rootdir}/includes/attributes.adoc[] - -= ContextFeature (webserver.context) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webserver.context/io/helidon/webserver/context/ContextFeature.html[io.helidon.webserver.context.ContextFeature] - - -[source,text] -.Config key ----- -context ----- - - -This type provides the following service implementations: - -- `io.helidon.webserver.spi.ServerFeatureProvider` - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`sockets` |string[] |{nbsp} |List of sockets to register this feature on. If empty, it would get registered on all sockets. - -Socket names to register on, defaults to empty (all available sockets) -|`weight` |double |`1100.0` |Weight of the context feature. As it is used by other features, the default is quite high: -io.helidon.webserver.context.ContextFeature.WEIGHT. - -Weight of the feature - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_cors_CorsConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_cors_CorsConfig.adoc deleted file mode 100644 index ee25c9fcf1e..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_cors_CorsConfig.adoc +++ /dev/null @@ -1,76 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.cors.CorsFeature -:keywords: helidon, config, io.helidon.webserver.cors.CorsFeature -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.cors.CorsFeature -include::{rootdir}/includes/attributes.adoc[] - -= CorsFeature (webserver.cors) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webserver.cors/io/helidon/webserver/cors/CorsFeature.html[io.helidon.webserver.cors.CorsFeature] - - -[source,text] -.Config key ----- -cors ----- - - -This type provides the following service implementations: - -- `io.helidon.webserver.spi.ServerFeatureProvider` - - -== Configuration options - -.Required configuration options -[cols="3,3a,2,5a"] -|=== -|key |type |default value |description - -|`enabled` |boolean |{nbsp} |This feature can be disabled. - -Whether the feature is enabled - -|=== - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`sockets` |string[] |{nbsp} |List of sockets to register this feature on. If empty, it would get registered on all sockets. - -Socket names to register on, defaults to empty (all available sockets) -|`weight` |double |`850.0` |Weight of the CORS feature. As it is used by other features, the default is quite high: -CorsFeature.WEIGHT. - -Weight of the feature - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_cors_CorsFeature.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_cors_CorsFeature.adoc deleted file mode 100644 index ee25c9fcf1e..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_cors_CorsFeature.adoc +++ /dev/null @@ -1,76 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.cors.CorsFeature -:keywords: helidon, config, io.helidon.webserver.cors.CorsFeature -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.cors.CorsFeature -include::{rootdir}/includes/attributes.adoc[] - -= CorsFeature (webserver.cors) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webserver.cors/io/helidon/webserver/cors/CorsFeature.html[io.helidon.webserver.cors.CorsFeature] - - -[source,text] -.Config key ----- -cors ----- - - -This type provides the following service implementations: - -- `io.helidon.webserver.spi.ServerFeatureProvider` - - -== Configuration options - -.Required configuration options -[cols="3,3a,2,5a"] -|=== -|key |type |default value |description - -|`enabled` |boolean |{nbsp} |This feature can be disabled. - -Whether the feature is enabled - -|=== - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`sockets` |string[] |{nbsp} |List of sockets to register this feature on. If empty, it would get registered on all sockets. - -Socket names to register on, defaults to empty (all available sockets) -|`weight` |double |`850.0` |Weight of the CORS feature. As it is used by other features, the default is quite high: -CorsFeature.WEIGHT. - -Weight of the feature - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_grpc_GrpcConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_grpc_GrpcConfig.adoc deleted file mode 100644 index 87d5f506f09..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_grpc_GrpcConfig.adoc +++ /dev/null @@ -1,49 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.grpc.GrpcConfig -:keywords: helidon, config, io.helidon.webserver.grpc.GrpcConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.grpc.GrpcConfig -include::{rootdir}/includes/attributes.adoc[] - -= GrpcConfig (webserver.grpc) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webserver.grpc/io/helidon/webserver/grpc/GrpcConfig.html[io.helidon.webserver.grpc.GrpcConfig] - - -[source,text] -.Config key ----- -grpc ----- - - -This type provides the following service implementations: - -- `io.helidon.webserver.spi.ProtocolConfigProvider` - - -== Configuration options - - - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_grpc_GrpcTracingConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_grpc_GrpcTracingConfig.adoc deleted file mode 100644 index 3bfc5e60bf7..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_grpc_GrpcTracingConfig.adoc +++ /dev/null @@ -1,51 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.grpc.GrpcTracingConfig -:keywords: helidon, config, io.helidon.webserver.grpc.GrpcTracingConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.grpc.GrpcTracingConfig -include::{rootdir}/includes/attributes.adoc[] - -= GrpcTracingConfig (webserver.grpc) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webserver.grpc/io/helidon/webserver/grpc/GrpcTracingConfig.html[io.helidon.webserver.grpc.GrpcTracingConfig] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`enabled` |boolean |`true` |A flag indicating if tracing is enabled. -|`streaming` |boolean |`false` |A flag indicating streaming logging. -|`verbose` |boolean |`false` |A flag indicating verbose logging. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_http1_Http1Config.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_http1_Http1Config.adoc deleted file mode 100644 index dfbd09abf48..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_http1_Http1Config.adoc +++ /dev/null @@ -1,102 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.http1.Http1Config -:keywords: helidon, config, io.helidon.webserver.http1.Http1Config -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.http1.Http1Config -include::{rootdir}/includes/attributes.adoc[] - -= Http1Config (webserver.http1) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webserver.http1/io/helidon/webserver/http1/Http1Config.html[io.helidon.webserver.http1.Http1Config] - - -[source,text] -.Config key ----- -http_1_1 ----- - - -This type provides the following service implementations: - -- `io.helidon.webserver.spi.ProtocolConfigProvider` - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`continue-immediately` |boolean |`false` |When true WebServer answers to expect continue with 100 continue immediately, -not waiting for user to actually request the data. - -If `true` answer with 100 continue immediately after expect continue -|`max-headers-size` |int |`16384` |Maximal size of received headers in bytes. - -Maximal header size -|`max-prologue-length` |int |`4096` |Maximal size of received HTTP prologue (GET /path HTTP/1.1). - -Maximal size in bytes -|`recv-log` |boolean |`true` |Logging of received packets. Uses trace and debug levels on logger of -Http1LoggingConnectionListener with suffix of `.recv``. - -`true` if logging should be enabled for received packets, `false` if no logging should be done -|`requested-uri-discovery` |xref:{rootdir}/config/io_helidon_http_RequestedUriDiscoveryContext.adoc[RequestedUriDiscoveryContext] |{nbsp} |Requested URI discovery settings. - -Settings for computing the requested URI -|`send-log` |boolean |`true` |Logging of sent packets. Uses trace and debug levels on logger of -Http1LoggingConnectionListener with suffix of `.send``. - -`true` if logging should be enabled for sent packets, `false` if no logging should be done -|`validate-path` |boolean |`true` |If set to false, any path is accepted (even containing illegal characters). - -Whether to validate path -|`validate-request-headers` |boolean |`true` |Whether to validate headers. -If set to false, any value is accepted, otherwise validates headers + known headers -are validated by format -(content length is always validated as it is part of protocol processing (other headers may be validated if -features use them)). - - Defaults to `true`. - - -Whether to validate headers -|`validate-response-headers` |boolean |`false` |Whether to validate headers. -If set to false, any value is accepted, otherwise validates headers + known headers -are validated by format -(content length is always validated as it is part of protocol processing (other headers may be validated if -features use them)). - - Defaults to `false` as user has control on the header creation. - - -Whether to validate headers - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_http2_Http2Config.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_http2_Http2Config.adoc deleted file mode 100644 index fd1e8bee832..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_http2_Http2Config.adoc +++ /dev/null @@ -1,128 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.http2.Http2Config -:keywords: helidon, config, io.helidon.webserver.http2.Http2Config -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.http2.Http2Config -include::{rootdir}/includes/attributes.adoc[] - -= Http2Config (webserver.http2) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webserver.http2/io/helidon/webserver/http2/Http2Config.html[io.helidon.webserver.http2.Http2Config] - - -[source,text] -.Config key ----- -http_2 ----- - - -This type provides the following service implementations: - -- `io.helidon.webserver.spi.ProtocolConfigProvider` - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`flow-control-timeout` |Duration |`PT0.1S` |Outbound flow control blocking timeout configured as java.time.Duration -or text in ISO-8601 format. -Blocking timeout defines an interval to wait for the outbound window size changes(incoming window updates) -before the next blocking iteration. -Default value is `PT0.1S`. - - -++++ - - - - - -
        *ISO_8601 format examples:*
        PT0.1S100 milliseconds
        PT0.5S500 milliseconds
        PT2S2 seconds
        -++++ - - -Duration -See https://en.wikipedia.org/wiki/ISO_8601.Durations[ISO_8601 Durations] -|`initial-window-size` |int |`1048576` |This setting indicates the sender's maximum window size in bytes for stream-level flow control. -Default and maximum value is 2^31^-1 = 2147483647 bytes. This setting affects the window size -of HTTP/2 connection. -Any value greater than 2147483647 causes an error. Any value smaller than initial window size causes an error. -See RFC 9113 section 6.9.1 for details. - -Maximum window size in bytes -|`max-concurrent-streams` |long |`8192` |Maximum number of concurrent streams that the server will allow. -Defaults to `8192`. This limit is directional: it applies to the number of streams that the sender -permits the receiver to create. -It is recommended that this value be no smaller than 100 to not unnecessarily limit parallelism -See RFC 9113 section 6.5.2 for details. - -Maximal number of concurrent streams -|`max-empty-frames` |int |`10` |Maximum number of consecutive empty frames allowed on connection. - -Max number of consecutive empty frames -|`max-frame-size` |int |`16384` |The size of the largest frame payload that the sender is willing to receive in bytes. -Default value is `16384` and maximum value is 2^24^-1 = 16777215 bytes. -See RFC 9113 section 6.5.2 for details. - -Maximal frame size -|`max-header-list-size` |long |`8192` |The maximum field section size that the sender is prepared to accept in bytes. -See RFC 9113 section 6.5.2 for details. -Default is 8192. - -Maximal header list size in bytes -|`max-rapid-resets` |int |`100` |Maximum number of rapid resets(stream RST sent by client before any data have been sent by server). -When reached within rapidResetCheckPeriod(), GOAWAY is sent to client and connection is closed. -Default value is `100`. - -Maximum number of rapid resets -See https://nvd.nist.gov/vuln/detail/CVE-2023-44487[CVE-2023-44487] -|`rapid-reset-check-period` |Duration |`PT10S` |Period for counting rapid resets(stream RST sent by client before any data have been sent by server). -Default value is `PT10S`. - -Duration -See https://nvd.nist.gov/vuln/detail/CVE-2023-44487[CVE-2023-44487] -See https://en.wikipedia.org/wiki/ISO_8601.Durations[ISO_8601 Durations] -|`requested-uri-discovery` |xref:{rootdir}/config/io_helidon_http_RequestedUriDiscoveryContext.adoc[RequestedUriDiscoveryContext] |{nbsp} |Requested URI discovery settings. - -Settings for computing the requested URI -|`send-error-details` |boolean |`false` |Whether to send error message over HTTP to client. -Defaults to `false`, as exception message may contain internal information that could be used as an -attack vector. Use with care and in cases where both server and clients are under your full control (such as for -testing). - -Whether to send error messages over the network -|`validate-path` |boolean |`true` |If set to false, any path is accepted (even containing illegal characters). - -Whether to validate path - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_ObserveFeature.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_observe_ObserveFeature.adoc deleted file mode 100644 index 5244d9fc584..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_ObserveFeature.adoc +++ /dev/null @@ -1,96 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.observe.ObserveFeature -:keywords: helidon, config, io.helidon.webserver.observe.ObserveFeature -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.observe.ObserveFeature -include::{rootdir}/includes/attributes.adoc[] - -= ObserveFeature (webserver.observe) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webserver.observe/io/helidon/webserver/observe/ObserveFeature.html[io.helidon.webserver.observe.ObserveFeature] - - -[source,text] -.Config key ----- -observe ----- - - -This type provides the following service implementations: - -- `io.helidon.webserver.spi.ServerFeatureProvider` - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`cors` |xref:{rootdir}/config/io_helidon_cors_CrossOriginConfig.adoc[CrossOriginConfig] |`@io.helidon.cors.CrossOriginConfig@.create()` |Cors support inherited by each observe provider, unless explicitly configured. - -Cors support to use -|`enabled` |boolean |`true` |Whether the observe support is enabled. - -`false` to disable observe feature -|`endpoint` |string |`/observe` |Root endpoint to use for observe providers. By default, all observe endpoint are under this root endpoint. - -Example: - -If root endpoint is `/observe` (the default), and default health endpoint is `health` (relative), -health endpoint would be `/observe/health`. - -Endpoint to use -|`observers` |io.helidon.webserver.observe.spi.Observer[] (service provider interface) - -Such as: - - - xref:{rootdir}/config/io_helidon_webserver_observe_log_LogObserver.adoc[log (LogObserver)] - - xref:{rootdir}/config/io_helidon_webserver_observe_tracing_TracingObserver.adoc[tracing (TracingObserver)] - - xref:{rootdir}/config/io_helidon_webserver_observe_config_ConfigObserver.adoc[config (ConfigObserver)] - - xref:{rootdir}/config/io_helidon_webserver_observe_info_InfoObserver.adoc[info (InfoObserver)] - - xref:{rootdir}/config/io_helidon_webserver_observe_metrics_MetricsObserver.adoc[metrics (MetricsObserver)] - - xref:{rootdir}/config/io_helidon_webserver_observe_health_HealthObserver.adoc[health (HealthObserver)] - - |{nbsp} |Observers to use with this observe features. -Each observer type is registered only once, unless it uses a custom name (default name is the same as the type). - -List of observers to use in this feature -|`sockets` |string[] |{nbsp} |Sockets the observability endpoint should be exposed on. If not defined, defaults to the default socket -(io.helidon.webserver.WebServer.DEFAULT_SOCKET_NAME. -Each observer may have its own configuration of sockets that are relevant to it, this only controls the endpoints! - -List of sockets to register observe endpoint on -|`weight` |double |`80.0` |Change the weight of this feature. This may change the order of registration of this feature. -By default, observability weight is ObserveFeature.WEIGHT so it is registered after routing. - -Weight to use - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_ObserverConfigBase.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_observe_ObserverConfigBase.adoc deleted file mode 100644 index 36a34c8816e..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_ObserverConfigBase.adoc +++ /dev/null @@ -1,51 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.observe.ObserverConfigBase -:keywords: helidon, config, io.helidon.webserver.observe.ObserverConfigBase -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.observe.ObserverConfigBase -include::{rootdir}/includes/attributes.adoc[] - -= ObserverConfigBase (webserver.observe) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webserver.observe/io/helidon/webserver/observe/ObserverConfigBase.html[io.helidon.webserver.observe.ObserverConfigBase] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`enabled` |boolean |`true` |Whether this observer is enabled. - -`false` to disable observer - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_config_ConfigObserver.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_observe_config_ConfigObserver.adoc deleted file mode 100644 index 1fb7e003355..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_config_ConfigObserver.adoc +++ /dev/null @@ -1,72 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.observe.config.ConfigObserver -:keywords: helidon, config, io.helidon.webserver.observe.config.ConfigObserver -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.observe.config.ConfigObserver -include::{rootdir}/includes/attributes.adoc[] - -= ConfigObserver (webserver.observe.config) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webserver.observe.config/io/helidon/webserver/observe/config/ConfigObserver.html[io.helidon.webserver.observe.config.ConfigObserver] - - -[source,text] -.Config key ----- -config ----- - - -This type provides the following service implementations: - -- `io.helidon.webserver.observe.spi.ObserveProvider` - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`endpoint` |string |`config` | -|`permit-all` |boolean |{nbsp} |Permit all access, even when not authorized. - -Whether to permit access for anybody -|`secrets` |string[] |`.*password, .*passphrase, .*secret` |Secret patterns (regular expressions) to exclude from output. -Any pattern that matches a key will cause the output to be obfuscated and not contain the value. - -Patterns always added: - -- `.*password` -- `.*passphrase` -- `.*secret` - -Set of regular expression patterns for keys, where values should be excluded from output - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_health_HealthObserver.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_observe_health_HealthObserver.adoc deleted file mode 100644 index a90b9b1a25e..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_health_HealthObserver.adoc +++ /dev/null @@ -1,68 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.observe.health.HealthObserver -:keywords: helidon, config, io.helidon.webserver.observe.health.HealthObserver -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.observe.health.HealthObserver -include::{rootdir}/includes/attributes.adoc[] - -= HealthObserver (webserver.observe.health) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webserver.observe.health/io/helidon/webserver/observe/health/HealthObserver.html[io.helidon.webserver.observe.health.HealthObserver] - - -This is a standalone configuration type, prefix from configuration root: `health` - - -This type provides the following service implementations: - -- `io.helidon.webserver.observe.spi.ObserveProvider` - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`details` |boolean |`false` |Whether details should be printed. -By default, health only returns a io.helidon.http.Status.NO_CONTENT_204 for success, -io.helidon.http.Status.SERVICE_UNAVAILABLE_503 for health down, -and io.helidon.http.Status.INTERNAL_SERVER_ERROR_500 in case of error with no entity. -When details are enabled, health returns io.helidon.http.Status.OK_200 for success, same codes -otherwise -and a JSON entity with detailed information about each health check executed. - -Set to `true` to enable details -|`endpoint` |string |`health` | -|`use-system-services` |boolean |`true` |Whether to use services discovered by java.util.ServiceLoader. -By default, all io.helidon.health.spi.HealthCheckProvider based health checks are added. - -Set to `false` to disable discovery - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_info_InfoObserver.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_observe_info_InfoObserver.adoc deleted file mode 100644 index 6872c65ac7d..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_info_InfoObserver.adoc +++ /dev/null @@ -1,62 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.observe.info.InfoObserver -:keywords: helidon, config, io.helidon.webserver.observe.info.InfoObserver -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.observe.info.InfoObserver -include::{rootdir}/includes/attributes.adoc[] - -= InfoObserver (webserver.observe.info) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webserver.observe.info/io/helidon/webserver/observe/info/InfoObserver.html[io.helidon.webserver.observe.info.InfoObserver] - - -[source,text] -.Config key ----- -info ----- - - -This type provides the following service implementations: - -- `io.helidon.webserver.observe.spi.ObserveProvider` - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`endpoint` |string |`info` | -|`values` |Map<string, string> |{nbsp} |Values to be exposed using this observability endpoint. - -Value map - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_log_LogObserver.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_observe_log_LogObserver.adoc deleted file mode 100644 index d025673dd62..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_log_LogObserver.adoc +++ /dev/null @@ -1,65 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.observe.log.LogObserver -:keywords: helidon, config, io.helidon.webserver.observe.log.LogObserver -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.observe.log.LogObserver -include::{rootdir}/includes/attributes.adoc[] - -= LogObserver (webserver.observe.log) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webserver.observe.log/io/helidon/webserver/observe/log/LogObserver.html[io.helidon.webserver.observe.log.LogObserver] - - -[source,text] -.Config key ----- -log ----- - - -This type provides the following service implementations: - -- `io.helidon.webserver.observe.spi.ObserveProvider` - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`endpoint` |string |`log` | -|`permit-all` |boolean |{nbsp} |Permit all access, even when not authorized. - -Whether to permit access for anybody -|`stream` |xref:{rootdir}/config/io_helidon_webserver_observe_log_LogStreamConfig.adoc[LogStreamConfig] |`@io.helidon.webserver.observe.log.LogStreamConfig@.create()` |Configuration of log stream. - -Log stream configuration - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_log_LogStreamConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_observe_log_LogStreamConfig.adoc deleted file mode 100644 index bdfbe38769d..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_log_LogStreamConfig.adoc +++ /dev/null @@ -1,65 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.observe.log.LogStreamConfig -:keywords: helidon, config, io.helidon.webserver.observe.log.LogStreamConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.observe.log.LogStreamConfig -include::{rootdir}/includes/attributes.adoc[] - -= LogStreamConfig (webserver.observe.log) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webserver.observe.log/io/helidon/webserver/observe/log/LogStreamConfig.html[io.helidon.webserver.observe.log.LogStreamConfig] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`content-type` |HttpMediaType |`@io.helidon.http.HttpMediaTypes@.PLAINTEXT_UTF_8` | -|`enabled` |boolean |`true` |Whether stream is enabled. - -Whether to allow streaming of log statements -|`idle-message-timeout` |Duration |`PT5S` |How long to wait before we send the idle message, to make sure we keep the stream alive. - -If no messages appear within this duration, and idle message will be sent -See idleString() -|`idle-string` |string |`% -` |String sent when there are no log messages within the idleMessageTimeout(). - -String to write over the network when no log messages are received -|`queue-size` |int |`100` |Length of the in-memory queue that buffers log messages from loggers before sending them over the network. -If the messages are produced faster than we can send them to client, excess messages are DISCARDED, and will not -be sent. - -Size of the in-memory queue for log messages - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_metrics_MetricsObserver.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_observe_metrics_MetricsObserver.adoc deleted file mode 100644 index 6f968b52e26..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_metrics_MetricsObserver.adoc +++ /dev/null @@ -1,97 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.observe.metrics.MetricsObserver -:keywords: helidon, config, io.helidon.webserver.observe.metrics.MetricsObserver -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.observe.metrics.MetricsObserver -include::{rootdir}/includes/attributes.adoc[] - -= MetricsObserver (webserver.observe.metrics) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webserver.observe.metrics/io/helidon/webserver/observe/metrics/MetricsObserver.html[io.helidon.webserver.observe.metrics.MetricsObserver] - - -This is a standalone configuration type, prefix from configuration root: `metrics` - - -This type provides the following service implementations: - -- `io.helidon.webserver.observe.spi.ObserveProvider` - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`app-name` |string |{nbsp} |Value for the application tag to be added to each meter ID. - -Application tag value -|`app-tag-name` |string |{nbsp} |Name for the application tag to be added to each meter ID. - -Application tag name -|`enabled` |boolean |`true` |Whether metrics functionality is enabled. - -If metrics are configured to be enabled -|`endpoint` |string |`metrics` | -|[.line-through]#`gc-time-type`# |GcTimeType (GAUGE, COUNTER) |`GcTimeType.COUNTER` |*Deprecated* Whether the `gc.time` meter should be registered as a gauge (vs. a counter). -The `gc.time` meter is inspired by the MicroProfile Metrics spec, in which the meter was originally checked to -be a counter but starting in 5.1 was checked be a gauge. For the duration of Helidon 4.x users can choose which -type of meter Helidon registers for `gc.time`. -The type of meter to use for registering `gc.time` -@deprecated Provided for backward compatibility only; no replacement - -Allowed values: - -- `GAUGE`: Implement the meter as a gauge. This is backward-incompatible with Helidon 4.0.x releases but complies with -MicroProfile 5.1. -- `COUNTER`: Implement the meter as a counter. This is backward-compatible with Helidon 4.0.x releases but does not comply with -MicroProfile 5.1. - -|`key-performance-indicators` |xref:{rootdir}/config/io_helidon_metrics_api_KeyPerformanceIndicatorMetricsConfig.adoc[KeyPerformanceIndicatorMetricsConfig] |{nbsp} |Key performance indicator metrics settings. - -Key performance indicator metrics settings -|`permit-all` |boolean |`true` |Whether to allow anybody to access the endpoint. - -Whether to permit access to metrics endpoint to anybody, defaults to `true` -See roles() -|`rest-request-enabled` |boolean |`false` |Whether automatic REST request metrics should be measured. - -True/false -|`roles` |string[] |`observe` |Hints for role names the user is expected to be in. - -List of hints -|`scoping` |xref:{rootdir}/config/io_helidon_metrics_api_ScopingConfig.adoc[ScopingConfig] |{nbsp} |Settings related to scoping management. - -Scoping settings -|`tags` |xref:{rootdir}/config/io_helidon_metrics_api_Tag.adoc[Tag[]] |{nbsp} |Global tags. - -Name/value pairs for global tags - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_tracing_TracingObserver.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_observe_tracing_TracingObserver.adoc deleted file mode 100644 index a20fec9e836..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_observe_tracing_TracingObserver.adoc +++ /dev/null @@ -1,92 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.observe.tracing.TracingObserver -:keywords: helidon, config, io.helidon.webserver.observe.tracing.TracingObserver -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.observe.tracing.TracingObserver -include::{rootdir}/includes/attributes.adoc[] - -= TracingObserver (webserver.observe.tracing) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webserver.observe.tracing/io/helidon/webserver/observe/tracing/TracingObserver.html[io.helidon.webserver.observe.tracing.TracingObserver] - - -[source,text] -.Config key ----- -tracing ----- - - -This type provides the following service implementations: - -- `io.helidon.webserver.observe.spi.ObserveProvider` - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`env-config` |TracingConfig |`TracingConfig.ENABLED` |Use the provided configuration as a default for any request. - -Default web server tracing configuration -|`paths` |PathTracingConfig[] |`new @java.util.ArrayList@(@java.util.List@.of(PathTracingConfig.builder() - .path("/metrics/*") - .tracingConfig(TracingConfig.DISABLED) - .build(), - PathTracingConfig.builder() - .path("/observe/metrics/*") - .tracingConfig(TracingConfig.DISABLED) - .build(), - PathTracingConfig.builder() - .path("/health/*") - .tracingConfig(TracingConfig.DISABLED) - .build(), - PathTracingConfig.builder() - .path("/observe/health/*") - .tracingConfig(TracingConfig.DISABLED) - .build(), - PathTracingConfig.builder() - .path("/openapi/*") - .tracingConfig(TracingConfig.DISABLED) - .build(), - PathTracingConfig.builder() - .path("/observe/openapi/*") - .tracingConfig(TracingConfig.DISABLED) - .build()))` |Path specific configuration of tracing. - -Configuration of tracing for specific paths -|`weight` |double |`900.0` |Weight of the feature registered with WebServer. -Changing weight may cause tracing to be executed at a different time (such as after security, or even after -all routes). Please understand feature weights before changing this order. - -Weight of tracing feature - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_security_PathsConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_security_PathsConfig.adoc deleted file mode 100644 index b653473b436..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_security_PathsConfig.adoc +++ /dev/null @@ -1,89 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.security.PathsConfig -:keywords: helidon, config, io.helidon.webserver.security.PathsConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.security.PathsConfig -include::{rootdir}/includes/attributes.adoc[] - -= PathsConfig (webserver.security) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webserver.security/io/helidon/webserver/security/PathsConfig.html[io.helidon.webserver.security.PathsConfig] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`audit` |boolean |{nbsp} |Whether to audit this request - defaults to false, if enabled, request is audited with event type "request". - -Whether to audit -|`audit-event-type` |string |{nbsp} |Override for event-type, defaults to SecurityHandler.DEFAULT_AUDIT_EVENT_TYPE. - -Audit event type to use -|`audit-message-format` |string |{nbsp} |Override for audit message format, defaults to SecurityHandler.DEFAULT_AUDIT_MESSAGE_FORMAT. - -Audit message format to use -|`authenticate` |boolean |{nbsp} |If called, request will go through authentication process - defaults to false (even if authorize is true). - -Whether to authenticate or not -|`authentication-optional` |boolean |{nbsp} |If called, authentication failure will not abort request and will continue as anonymous (defaults to false). - -Whether authn is optional -|`authenticator` |string |{nbsp} |Use a named authenticator (as supported by security - if not defined, default authenticator is used). -Will enable authentication. - -Name of authenticator as configured in io.helidon.security.Security -|`authorize` |boolean |{nbsp} |Enable authorization for this route. - -Whether to authorize -|`authorizer` |string |{nbsp} |Use a named authorizer (as supported by security - if not defined, default authorizer is used, if none defined, all is -permitted). -Will enable authorization. - -Name of authorizer as configured in io.helidon.security.Security -|`methods` |Method[] |{nbsp} | -|`path` |string |{nbsp} | -|`roles-allowed` |string[] |{nbsp} |An array of allowed roles for this path - must have a security provider supporting roles (either authentication -or authorization provider). -This method enables authentication and authorization (you can disable them again by calling -SecurityHandler.skipAuthorization() -and authenticationOptional() if needed). - -If subject is any of these roles, allow access -|`sockets` |string[] |`@default` | -|`sockets` |string[] |{nbsp} |List of sockets this configuration should be applied to. -If empty, the configuration is applied to all configured sockets. - -List of sockets - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_security_SecurityFeature.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_security_SecurityFeature.adoc deleted file mode 100644 index ae75399478c..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_security_SecurityFeature.adoc +++ /dev/null @@ -1,76 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.security.SecurityFeature -:keywords: helidon, config, io.helidon.webserver.security.SecurityFeature -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.security.SecurityFeature -include::{rootdir}/includes/attributes.adoc[] - -= SecurityFeature (webserver.security) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webserver.security/io/helidon/webserver/security/SecurityFeature.html[io.helidon.webserver.security.SecurityFeature] - - -[source,text] -.Config key ----- -security ----- - - -This type provides the following service implementations: - -- `io.helidon.webserver.spi.ServerFeatureProvider` - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`defaults` |xref:{rootdir}/config/io_helidon_webserver_security_SecurityHandler.adoc[SecurityHandler] |`SecurityHandler.create()` |The default security handler. - -Security handler defaults -|`paths` |xref:{rootdir}/config/io_helidon_webserver_security_PathsConfig.adoc[PathsConfig[]] |{nbsp} |Configuration for webserver paths. - -Path configuration -|`security` |xref:{rootdir}/config/io_helidon_security_Security.adoc[Security] |{nbsp} |Security associated with this feature. -If not specified here, the feature uses security registered with -io.helidon.common.context.Contexts.globalContext(), if not found, it creates a new -instance from root of configuration (using `security` key). - -This configuration allows usage of a different security instance for a specific security feature setup. - -Security instance to be used to handle security in this feature configuration -|`weight` |double |`800.0` |Weight of the security feature. Value is: -io.helidon.webserver.security.SecurityFeature.WEIGHT. - -Weight of the feature - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_security_SecurityHandler.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_security_SecurityHandler.adoc deleted file mode 100644 index 24e592fb2bb..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_security_SecurityHandler.adoc +++ /dev/null @@ -1,86 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.security.SecurityHandler -:keywords: helidon, config, io.helidon.webserver.security.SecurityHandler -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.security.SecurityHandler -include::{rootdir}/includes/attributes.adoc[] - -= SecurityHandler (webserver.security) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webserver.security/io/helidon/webserver/security/SecurityHandler.html[io.helidon.webserver.security.SecurityHandler] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`audit` |boolean |{nbsp} |Whether to audit this request - defaults to false, if enabled, request is audited with event type "request". - -Whether to audit -|`audit-event-type` |string |{nbsp} |Override for event-type, defaults to SecurityHandler.DEFAULT_AUDIT_EVENT_TYPE. - -Audit event type to use -|`audit-message-format` |string |{nbsp} |Override for audit message format, defaults to SecurityHandler.DEFAULT_AUDIT_MESSAGE_FORMAT. - -Audit message format to use -|`authenticate` |boolean |{nbsp} |If called, request will go through authentication process - defaults to false (even if authorize is true). - -Whether to authenticate or not -|`authentication-optional` |boolean |{nbsp} |If called, authentication failure will not abort request and will continue as anonymous (defaults to false). - -Whether authn is optional -|`authenticator` |string |{nbsp} |Use a named authenticator (as supported by security - if not defined, default authenticator is used). -Will enable authentication. - -Name of authenticator as configured in io.helidon.security.Security -|`authorize` |boolean |{nbsp} |Enable authorization for this route. - -Whether to authorize -|`authorizer` |string |{nbsp} |Use a named authorizer (as supported by security - if not defined, default authorizer is used, if none defined, all is -permitted). -Will enable authorization. - -Name of authorizer as configured in io.helidon.security.Security -|`roles-allowed` |string[] |{nbsp} |An array of allowed roles for this path - must have a security provider supporting roles (either authentication -or authorization provider). -This method enables authentication and authorization (you can disable them again by calling -SecurityHandler.skipAuthorization() -and authenticationOptional() if needed). - -If subject is any of these roles, allow access -|`sockets` |string[] |{nbsp} |List of sockets this configuration should be applied to. -If empty, the configuration is applied to all configured sockets. - -List of sockets - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_servicecommon_HelidonFeatureSupport_Builder.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_servicecommon_HelidonFeatureSupport_Builder.adoc deleted file mode 100644 index 3f08c74d1a4..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_servicecommon_HelidonFeatureSupport_Builder.adoc +++ /dev/null @@ -1,50 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.servicecommon.HelidonFeatureSupport.Builder -:keywords: helidon, config, io.helidon.webserver.servicecommon.HelidonFeatureSupport.Builder -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.servicecommon.HelidonFeatureSupport.Builder -include::{rootdir}/includes/attributes.adoc[] - -= Builder (webserver.servicecommon.HelidonFeatureSupport) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webserver.servicecommon.HelidonFeatureSupport/io/helidon/webserver/servicecommon/HelidonFeatureSupport/Builder.html[io.helidon.webserver.servicecommon.HelidonFeatureSupport.Builder] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`cross-origin-config` |xref:{rootdir}/config/io_helidon_cors_CrossOriginConfig.adoc[CrossOriginConfig] |{nbsp} |Set the CORS config from the specified `CrossOriginConfig` object. -|`web-context` |string |{nbsp} |Set the root context for the REST API of the service. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_servicecommon_RestServiceSettings.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_servicecommon_RestServiceSettings.adoc deleted file mode 100644 index 5ba9b0a23f5..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_servicecommon_RestServiceSettings.adoc +++ /dev/null @@ -1,52 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.servicecommon.RestServiceSettings -:keywords: helidon, config, io.helidon.webserver.servicecommon.RestServiceSettings -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.servicecommon.RestServiceSettings -include::{rootdir}/includes/attributes.adoc[] - -= RestServiceSettings (webserver.servicecommon) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webserver.servicecommon/io/helidon/webserver/servicecommon/RestServiceSettings.html[io.helidon.webserver.servicecommon.RestServiceSettings] - - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`cors` |xref:{rootdir}/config/io_helidon_cors_CrossOriginConfig.adoc[Map<string, CrossOriginConfig>] |{nbsp} |Sets the cross-origin config builder for use in establishing CORS support for the service endpoints. -|`enabled` |boolean |`true` |Is this service enabled or not. -|`routing` |string |{nbsp} |Sets the routing name to use for setting up the service's endpoint. -|`web-context` |string |{nbsp} |Sets the web context to use for the service's endpoint. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_helidon_webserver_websocket_WsConfig.adoc b/docs/src/main/asciidoc/config/io_helidon_webserver_websocket_WsConfig.adoc deleted file mode 100644 index f5f49945de5..00000000000 --- a/docs/src/main/asciidoc/config/io_helidon_webserver_websocket_WsConfig.adoc +++ /dev/null @@ -1,68 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.helidon.webserver.websocket.WsConfig -:keywords: helidon, config, io.helidon.webserver.websocket.WsConfig -:basic-table-intro: The table below lists the configuration keys that configure io.helidon.webserver.websocket.WsConfig -include::{rootdir}/includes/attributes.adoc[] - -= WsConfig (webserver.websocket) Configuration - -// tag::config[] - - -Type: link:{javadoc-base-url}/io.helidon.webserver.websocket/io/helidon/webserver/websocket/WsConfig.html[io.helidon.webserver.websocket.WsConfig] - - -[source,text] -.Config key ----- -websocket ----- - - -This type provides the following service implementations: - -- `io.helidon.webserver.spi.ProtocolConfigProvider` - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`max-frame-length` |int |`1048576` |Max WebSocket frame size supported by the server on a read operation. -Default is 1 MB. - -Max frame size to read -|`name` |string |`websocket` |Name of this configuration. - -Configuration name -|`origins` |string[] |{nbsp} |WebSocket origins. - -Origins - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/io_opentracing_Tracer.adoc b/docs/src/main/asciidoc/config/io_opentracing_Tracer.adoc deleted file mode 100644 index 42bed06586c..00000000000 --- a/docs/src/main/asciidoc/config/io_opentracing_Tracer.adoc +++ /dev/null @@ -1,60 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023, 2024 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of io.opentracing.Tracer -:keywords: helidon, config, io.opentracing.Tracer -:basic-table-intro: The table below lists the configuration keys that configure io.opentracing.Tracer -include::{rootdir}/includes/attributes.adoc[] - -= io.opentracing.Tracer Configuration - -// tag::config[] - -Zipkin tracer configuration - - -Type: io.opentracing.Tracer - - -This is a standalone configuration type, prefix from configuration root: `tracing` - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`api-version` |Version (V1, V2) |`V2` |Version of Zipkin API to use. -Defaults to Version.V2. - -Allowed values: - -- `V1`: Version 1. -- `V2`: Version 2. - - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/config/org_eclipse_microprofile_config_Config.adoc b/docs/src/main/asciidoc/config/org_eclipse_microprofile_config_Config.adoc deleted file mode 100644 index 15222991777..00000000000 --- a/docs/src/main/asciidoc/config/org_eclipse_microprofile_config_Config.adoc +++ /dev/null @@ -1,51 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2023 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. - -/////////////////////////////////////////////////////////////////////////////// - -ifndef::rootdir[:rootdir: {docdir}/..] -:description: Configuration of org.eclipse.microprofile.config.Config -:keywords: helidon, config, org.eclipse.microprofile.config.Config -:basic-table-intro: The table below lists the configuration keys that configure org.eclipse.microprofile.config.Config -include::{rootdir}/includes/attributes.adoc[] - -= org.eclipse.microprofile.config.Config Configuration - -// tag::config[] - - -Type: org.eclipse.microprofile.config.Config - - -This is a standalone configuration type, prefix from configuration root: `mp.config` - - - -== Configuration options - - - -.Optional configuration options -[cols="3,3a,2,5a"] - -|=== -|key |type |default value |description - -|`profile` |string |{nbsp} |Configure an explicit profile name. - -|=== - -// end::config[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/mp/lra.adoc b/docs/src/main/asciidoc/mp/lra.adoc index b1cdddd6138..96a186976bd 100644 --- a/docs/src/main/asciidoc/mp/lra.adoc +++ b/docs/src/main/asciidoc/mp/lra.adoc @@ -294,7 +294,26 @@ include::{sourcedir}/mp/LraSnippets.java[tag=snippet_12, indent=0] == Configuration -include::{rootdir}/config/io_helidon_microprofile_lra_Coordinator.adoc[leveloffset=+1,tag=config] +[source,text] +.Type +---- +io.helidon.microprofile.lra +---- + +.Optional configuration options +[cols="3,3,2,5a"] + +|=== +|Key |Type |Default value |Description + +|`mp.lra.coordinator.url` |string |`\http://localhost:8070/lra-coordinator` |Url of coordinator. +|`mp.lra.coordinator.propagation.active` |boolean |{nbsp} |Propagate LRA headers `LRA_HTTP_CONTEXT_HEADER` and `LRA_HTTP_PARENT_CONTEXT_HEADER` through non-LRA endpoints. +|`mp.lara.participant.url` |string |{nbsp} |Url of the LRA enabled service overrides standard base uri, so coordinator can call load-balancer instead of the service. +|`mp.lra.coordinator.timeout` |string |{nbsp} |Timeout for synchronous communication with coordinator. +|`mp.lra.coordinator.timeout-unit` |string |{nbsp} |Timeout unit for synchronous communication with coordinator. + +|=== + [source,yaml] .Example of LRA configuration @@ -302,7 +321,7 @@ include::{rootdir}/config/io_helidon_microprofile_lra_Coordinator.adoc[leveloffs mp.lra: coordinator.url: http://localhost:8070/lra-coordinator <1> propagation.active: true <2> - participant.url: http://coordinator.visible.host:80/awesomeapp <3> + participant.url: https://coordinator.visible.host:443/awesomeapp <3> ---- <1> Url of coordinator <2> Propagate LRA headers LRA_HTTP_CONTEXT_HEADER and LRA_HTTP_PARENT_CONTEXT_HEADER through non-LRA endpoints From bc1ea3dfc8b677d997421bc8a39e8cdcb51253a3 Mon Sep 17 00:00:00 2001 From: Romain Grecourt Date: Mon, 5 Aug 2024 18:23:44 -0700 Subject: [PATCH 33/37] Refactor DbClient integration tests (#9104) - Use TestContainers, with oraclelinux based images - Add one sub-module per database, add modules for h2, mysql, pgsql, oracle, mongo - Add missing bom and all entry for helidon-integrations-db-pgsql Refactor tests/integration/harness - Removed all the suite support (potentially add back later in a different shape) - Re-worked HelidonProcessRunner, to mimic TestContainers --- all/pom.xml | 4 + bom/pom.xml | 5 + dependencies/pom.xml | 5 + docs/pom.xml | 5 + etc/copyright-exclude.txt | 1 + etc/pods/mysql.yaml | 35 - etc/pods/vault.yaml | 44 -- tests/integration/dbclient/app/pom.xml | 265 -------- .../dbclient/app/ErrorHandlerImpl.java | 42 -- .../integration/dbclient/app/InitService.java | 161 ----- .../tests/integration/dbclient/app/Main.java | 161 ----- .../dbclient/app/VerifyService.java | 94 --- .../app/dbmapper/DbClientMapperProvider.java | 44 -- .../app/dbmapper/DbRowToJsonObjectMapper.java | 150 ----- .../app/tests/AbstractDeleteService.java | 189 ------ .../app/tests/AbstractGetService.java | 130 ---- .../app/tests/AbstractInsertService.java | 250 ------- .../app/tests/AbstractQueryService.java | 136 ---- .../dbclient/app/tests/AbstractService.java | 88 --- .../app/tests/AbstractUpdateService.java | 206 ------ .../app/tests/FlowControlService.java | 102 --- .../app/tests/HealthCheckService.java | 147 ----- .../app/tests/InterceptorService.java | 92 --- .../dbclient/app/tests/MapperService.java | 223 ------- .../app/tests/SimpleDeleteService.java | 140 ---- .../dbclient/app/tests/SimpleGetService.java | 90 --- .../app/tests/SimpleInsertService.java | 150 ----- .../app/tests/SimpleQueryService.java | 97 --- .../app/tests/SimpleUpdateService.java | 150 ----- .../app/tests/StatementDmlService.java | 169 ----- .../app/tests/StatementGetService.java | 180 ----- .../app/tests/StatementQueryService.java | 182 ------ .../app/tests/TransactionDeleteService.java | 164 ----- .../app/tests/TransactionGetService.java | 104 --- .../app/tests/TransactionInsertService.java | 180 ----- .../app/tests/TransactionQueryService.java | 118 ---- .../app/tests/TransactionUpdateService.java | 180 ----- .../dbclient/app/tools/ExitService.java | 51 -- .../dbclient/app/tools/QueryParams.java | 94 --- .../dbclient/app/src/main/resources/h2.yaml | 61 -- .../app/src/main/resources/logging.properties | 25 - .../app/src/main/resources/mysql.yaml | 59 -- .../app/src/main/resources/pgsql.yaml | 61 -- .../integration/dbclient/app/DbInit.java | 115 ---- .../integration/dbclient/app/LogData.java | 70 -- .../integration/dbclient/app/SuiteIT.java | 147 ----- .../integration/dbclient/app/VerifyData.java | 82 --- .../dbclient/app/tests/FlowControlIT.java | 72 -- .../dbclient/app/tests/HealthCheckIT.java | 154 ----- .../dbclient/app/tests/InterceptorIT.java | 47 -- .../dbclient/app/tests/MapperIT.java | 178 ----- .../app/tests/ServerMetricsCheckIT.java | 86 --- .../dbclient/app/tests/SimpleDeleteIT.java | 178 ----- .../dbclient/app/tests/SimpleGetIT.java | 116 ---- .../dbclient/app/tests/SimpleInsertIT.java | 173 ----- .../dbclient/app/tests/SimpleQueriesIT.java | 117 ---- .../dbclient/app/tests/SimpleUpdateIT.java | 186 ------ .../dbclient/app/tests/StatementDmlIT.java | 126 ---- .../dbclient/app/tests/StatementGetIT.java | 128 ---- .../dbclient/app/tests/StatementQueryIT.java | 129 ---- .../app/tests/TransactionDeleteIT.java | 178 ----- .../dbclient/app/tests/TransactionGetIT.java | 116 ---- .../app/tests/TransactionInsertIT.java | 174 ----- .../app/tests/TransactionQueriesIT.java | 120 ---- .../app/tests/TransactionUpdateIT.java | 185 ------ .../app/src/test/resources/logging.properties | 25 - tests/integration/dbclient/common/pom.xml | 20 +- .../dbclient/common/AbstractTestImpl.java | 124 ++++ .../integration/dbclient/common/DBHelper.java | 64 ++ .../dbclient/common/DbClientITMain.java | 101 +++ .../dbclient/common/DbMapperProviderImpl.java | 87 +++ .../dbclient/common/LocalTextContext.java | 82 +++ .../dbclient/common/MapperProviderImpl.java | 47 ++ .../integration/dbclient/common/MiscTest.java | 73 +++ .../dbclient/common/MiscTestImpl.java | 189 ++++++ .../dbclient/common/ObservabilityTest.java | 68 ++ .../common/ObservabilityTestImpl.java | 197 ++++++ .../dbclient/common/RemoteTest.java | 61 ++ .../dbclient/common/SimpleTest.java} | 25 +- .../dbclient/common/SimpleTestImpl.java | 614 ++++++++++++++++++ .../dbclient/common/SimpleTests.java | 342 ++++++++++ .../SetupProvider.java => StatementTest.java} | 28 +- .../dbclient/common/StatementTestImpl.java | 381 +++++++++++ .../dbclient/common/StatementTests.java | 181 ++++++ .../dbclient/common/TestService.java | 107 +++ .../dbclient/common/TransactionTest.java | 27 + .../dbclient/common/TransactionTestImpl.java | 559 ++++++++++++++++ .../dbclient/common/TransactionTests.java | 258 ++++++++ .../dbclient/common/model/Pokemon.java | 227 +------ .../dbclient/common/model/Pokemons.java | 405 ++++++++++++ .../dbclient/common/model/Range.java} | 24 +- .../dbclient/common/model/RangePoJo.java | 90 --- .../dbclient/common/model/Type.java | 52 +- .../dbclient/common/model/Types.java | 152 +++++ .../tests/DbClientParameterResolver.java | 73 --- .../common/tests/ExceptionalStmtIT.java | 126 ---- .../dbclient/common/tests/FlowControlIT.java | 69 -- .../dbclient/common/tests/GetStatementIT.java | 141 ---- .../dbclient/common/tests/HealthCheckIT.java | 140 ---- .../dbclient/common/tests/InterceptorIT.java | 76 --- .../dbclient/common/tests/MapperIT.java | 195 ------ .../common/tests/QueryStatementIT.java | 162 ----- .../common/tests/ServerHealthCheckIT.java | 175 ----- .../common/tests/ServerMetricsCheckIT.java | 163 ----- .../dbclient/common/tests/SimpleDeleteIT.java | 158 ----- .../dbclient/common/tests/SimpleDmlIT.java | 368 ----------- .../dbclient/common/tests/SimpleGetIT.java | 127 ---- .../dbclient/common/tests/SimpleInsertIT.java | 138 ---- .../common/tests/SimpleQueriesIT.java | 129 ---- .../dbclient/common/tests/SimpleUpdateIT.java | 178 ----- .../dbclient/common/tests/StatementDmlIT.java | 175 ----- .../common/tests/TransactionDeleteIT.java | 184 ------ .../tests/TransactionExceptionalStmtIT.java | 134 ---- .../common/tests/TransactionGetIT.java | 148 ----- .../common/tests/TransactionInsertIT.java | 146 ----- .../common/tests/TransactionQueriesIT.java | 149 ----- .../common/tests/TransactionUpdateIT.java | 190 ------ .../dbclient/common/utils/MapperProvider.java | 40 -- .../dbclient/common/utils/RangePoJo.java | 92 --- .../dbclient/common/utils/TestConfig.java | 45 -- .../dbclient/common/utils/VerifyData.java | 198 ------ .../common/src/main/java/module-info.java | 46 -- ....helidon.common.mapper.spi.MapperProvider} | 5 +- .../io.helidon.dbclient.spi.DbMapperProvider | 4 +- .../common/src/main/resources/db-common.yaml | 68 ++ tests/integration/dbclient/h2/README.md | 6 + tests/integration/dbclient/h2/pom.xml | 104 +-- .../dbclient/jdbc/H2SetupProvider.java | 141 ---- .../dbclient/h2/src/main/resources/db.yaml | 31 +- .../src/main/resources/logging.properties} | 7 +- .../main/resources/simplelogger.properties | 22 + .../integration/dbclient/h2/H2LocalTest.java | 40 ++ .../dbclient/h2/H2MiscLocalTestIT.java | 102 +++ .../dbclient/h2/H2MiscRemoteTestIT.java | 90 +++ .../h2/H2ObservabilityLocalTestIT.java | 109 ++++ .../h2/H2ObservabilityRemoteTestIT.java | 84 +++ .../integration/dbclient/h2/H2RemoteTest.java | 49 ++ .../dbclient/h2/H2SimpleLocalTestIT.java | 378 +++++++++++ .../dbclient/h2/H2SimpleRemoteTestIT.java | 366 +++++++++++ .../dbclient/h2/H2StatementLocalTestIT.java | 204 ++++++ .../dbclient/h2/H2StatementRemoteTestIT.java | 191 ++++++ .../dbclient/h2/H2TransactionLocalTestIT.java | 282 ++++++++ .../h2/H2TransactionRemoteTestIT.java | 270 ++++++++ .../dbclient/h2/src/test/resources/h2.yaml | 63 -- tests/integration/dbclient/mongodb/README.md | 22 + .../dbclient/mongodb/etc/docker/Dockerfile | 26 + .../dbclient/mongodb/etc/docker/entrypoint.sh | 49 ++ .../mongodb/etc/docker/mongodb-org-7.0.repo | 6 + tests/integration/dbclient/mongodb/pom.xml | 89 +-- .../mongodb/src/main/resources/db.yaml | 202 ++++++ .../src/main/resources/logging.properties} | 6 +- .../main/resources/simplelogger.properties | 22 + .../dbclient/mongodb/MongoDBLocalTest.java | 40 ++ .../mongodb/MongoDBMiscLocalTestIT.java | 96 +++ .../mongodb/MongoDBMiscRemoteTestIT.java | 90 +++ .../MongoDBObservabilityLocalTestIT.java | 103 +++ .../MongoDBObservabilityRemoteTestIT.java | 84 +++ .../dbclient/mongodb/MongoDBRemoteTest.java | 58 ++ .../mongodb/MongoDBSimpleLocalTestIT.java | 372 +++++++++++ .../mongodb/MongoDBSimpleRemoteTestIT.java | 366 +++++++++++ .../mongodb/MongoDBStatementLocalTestIT.java | 198 ++++++ .../mongodb/MongoDBStatementRemoteTestIT.java | 192 ++++++ .../dbclient/mongodb/MongoDBSuiteIT.java | 202 ------ .../mongodb/MongoDBTestContainer.java | 53 ++ .../mongodb/src/test/resources/test.yaml | 206 ------ tests/integration/dbclient/mysql/README.md | 17 + tests/integration/dbclient/mysql/pom.xml | 80 +++ .../dbclient/mysql/src/main/resources/db.yaml | 30 + .../src/main/resources/logging.properties | 18 + .../main/resources/simplelogger.properties | 22 + .../dbclient/mysql/MySQLLocalTest.java | 40 ++ .../dbclient/mysql/MySQLMiscLocalTestIT.java | 96 +++ .../dbclient/mysql/MySQLMiscRemoteTestIT.java | 90 +++ .../mysql/MySQLObservabilityLocalTestIT.java | 103 +++ .../mysql/MySQLObservabilityRemoteTestIT.java | 84 +++ .../dbclient/mysql/MySQLRemoteTest.java | 58 ++ .../mysql/MySQLSimpleLocalTestIT.java | 372 +++++++++++ .../mysql/MySQLSimpleRemoteTestIT.java | 366 +++++++++++ .../mysql/MySQLStatementLocalTestIT.java | 198 ++++++ .../mysql/MySQLStatementRemoteTestIT.java | 192 ++++++ .../dbclient/mysql/MySQLTestContainer.java | 43 ++ .../mysql/MySQLTransactionLocalTestIT.java | 276 ++++++++ .../mysql/MySQLTransactionRemoteTestIT.java | 270 ++++++++ tests/integration/dbclient/oracle/README.md | 15 + tests/integration/dbclient/oracle/pom.xml | 71 ++ .../oracle/src/main/resources/db.yaml | 29 + .../src/main/resources/logging.properties | 18 + .../main/resources/simplelogger.properties | 22 + .../dbclient/oracle/OracleLocalTest.java | 40 ++ .../oracle/OracleMiscLocalTestIT.java | 96 +++ .../oracle/OracleMiscRemoteTestIT.java | 90 +++ .../OracleObservabilityLocalTestIT.java | 103 +++ .../OracleObservabilityRemoteTestIT.java | 84 +++ .../dbclient/oracle/OracleRemoteTest.java | 58 ++ .../oracle/OracleSimpleLocalTestIT.java | 372 +++++++++++ .../oracle/OracleSimpleRemoteTestIT.java | 366 +++++++++++ .../oracle/OracleStatementLocalTestIT.java | 198 ++++++ .../oracle/OracleStatementRemoteTestIT.java | 192 ++++++ .../dbclient/oracle/OracleTestContainer.java | 49 ++ .../oracle/OracleTransactionLocalTestIT.java | 276 ++++++++ .../oracle/OracleTransactionRemoteTestIT.java | 270 ++++++++ tests/integration/dbclient/parent/pom.xml | 151 +++++ tests/integration/dbclient/pgsql/README.md | 22 + .../dbclient/pgsql/etc/docker/Dockerfile | 27 + .../dbclient/pgsql/etc/docker/entrypoint.sh | 50 ++ tests/integration/dbclient/pgsql/pom.xml | 80 +++ .../dbclient/pgsql/src/main/resources/db.yaml | 28 + .../src/main/resources/logging.properties | 18 + .../main/resources/simplelogger.properties | 22 + .../dbclient/pgsql/PostgreSQLLocalTest.java | 40 ++ .../pgsql/PostgreSQLMiscLocalTestIT.java | 96 +++ .../pgsql/PostgreSQLMiscRemoteTestIT.java | 90 +++ .../PostgreSQLObservabilityLocalTestIT.java | 103 +++ .../PostgreSQLObservabilityRemoteTestIT.java | 84 +++ .../dbclient/pgsql/PostgreSQLRemoteTest.java | 58 ++ .../pgsql/PostgreSQLSimpleLocalTestIT.java | 372 +++++++++++ .../pgsql/PostgreSQLSimpleRemoteTestIT.java | 366 +++++++++++ .../pgsql/PostgreSQLStatementLocalTestIT.java | 198 ++++++ .../PostgreSQLStatementRemoteTestIT.java | 192 ++++++ .../pgsql/PostgreSQLTestContainer.java | 114 ++++ .../PostgreSQLTransactionLocalTestIT.java | 276 ++++++++ .../PostgreSQLTransactionRemoteTestIT.java | 270 ++++++++ tests/integration/dbclient/pom.xml | 32 +- tests/integration/harness/pom.xml | 22 +- .../tests/integration/harness/AfterSuite.java | 38 -- .../integration/harness/AppResponse.java | 112 ---- .../harness/HelidonProcessRunner.java | 480 -------------- .../harness/HelidonTestException.java | 44 -- .../tests/integration/harness/JsonValues.java | 62 -- .../tests/integration/harness/PathFinder.java | 86 +++ .../integration/harness/ProcessMonitor.java | 191 ++++++ .../integration/harness/ProcessRunner.java | 500 ++++++++++++++ .../harness/ProcessRunnerExtension.java | 111 ++++ .../harness/RemoteTestException.java | 41 -- .../integration/harness/SuiteContext.java | 105 --- .../integration/harness/SuiteFinder.java | 99 --- .../integration/harness/SuiteLifeCycle.java | 166 ----- .../harness/SuiteParameterResolver.java | 51 -- .../tests/integration/harness/TestClient.java | 286 -------- .../harness/{SetUp.java => TestProcess.java} | 19 +- .../{BeforeSuite.java => TestProcesses.java} | 21 +- .../harness/TestServiceClient.java | 120 ---- .../integration/harness/WaitStrategy.java | 220 +++++++ 243 files changed, 16981 insertions(+), 14570 deletions(-) delete mode 100644 etc/pods/mysql.yaml delete mode 100644 etc/pods/vault.yaml delete mode 100644 tests/integration/dbclient/app/pom.xml delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/ErrorHandlerImpl.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/InitService.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/Main.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/VerifyService.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/dbmapper/DbClientMapperProvider.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/dbmapper/DbRowToJsonObjectMapper.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/AbstractDeleteService.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/AbstractGetService.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/AbstractInsertService.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/AbstractQueryService.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/AbstractService.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/AbstractUpdateService.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/FlowControlService.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/HealthCheckService.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/InterceptorService.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/MapperService.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/SimpleDeleteService.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/SimpleGetService.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/SimpleInsertService.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/SimpleQueryService.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/SimpleUpdateService.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/StatementDmlService.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/StatementGetService.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/StatementQueryService.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/TransactionDeleteService.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/TransactionGetService.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/TransactionInsertService.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/TransactionQueryService.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/TransactionUpdateService.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tools/ExitService.java delete mode 100644 tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tools/QueryParams.java delete mode 100644 tests/integration/dbclient/app/src/main/resources/h2.yaml delete mode 100644 tests/integration/dbclient/app/src/main/resources/logging.properties delete mode 100644 tests/integration/dbclient/app/src/main/resources/mysql.yaml delete mode 100644 tests/integration/dbclient/app/src/main/resources/pgsql.yaml delete mode 100644 tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/DbInit.java delete mode 100644 tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/LogData.java delete mode 100644 tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/SuiteIT.java delete mode 100644 tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/VerifyData.java delete mode 100644 tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/FlowControlIT.java delete mode 100644 tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/HealthCheckIT.java delete mode 100644 tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/InterceptorIT.java delete mode 100644 tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/MapperIT.java delete mode 100644 tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/ServerMetricsCheckIT.java delete mode 100644 tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/SimpleDeleteIT.java delete mode 100644 tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/SimpleGetIT.java delete mode 100644 tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/SimpleInsertIT.java delete mode 100644 tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/SimpleQueriesIT.java delete mode 100644 tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/SimpleUpdateIT.java delete mode 100644 tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/StatementDmlIT.java delete mode 100644 tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/StatementGetIT.java delete mode 100644 tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/StatementQueryIT.java delete mode 100644 tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/TransactionDeleteIT.java delete mode 100644 tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/TransactionGetIT.java delete mode 100644 tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/TransactionInsertIT.java delete mode 100644 tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/TransactionQueriesIT.java delete mode 100644 tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/TransactionUpdateIT.java delete mode 100644 tests/integration/dbclient/app/src/test/resources/logging.properties create mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/AbstractTestImpl.java create mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/DBHelper.java create mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/DbClientITMain.java create mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/DbMapperProviderImpl.java create mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/LocalTextContext.java create mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/MapperProviderImpl.java create mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/MiscTest.java create mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/MiscTestImpl.java create mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/ObservabilityTest.java create mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/ObservabilityTestImpl.java create mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/RemoteTest.java rename tests/integration/dbclient/{h2/src/main/java/module-info.java => common/src/main/java/io/helidon/tests/integration/dbclient/common/SimpleTest.java} (53%) create mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/SimpleTestImpl.java create mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/SimpleTests.java rename tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/{spi/SetupProvider.java => StatementTest.java} (55%) create mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/StatementTestImpl.java create mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/StatementTests.java create mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/TestService.java create mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/TransactionTest.java create mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/TransactionTestImpl.java create mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/TransactionTests.java create mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/model/Pokemons.java rename tests/integration/{harness/src/main/java/module-info.java => dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/model/Range.java} (53%) delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/model/RangePoJo.java create mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/model/Types.java delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/DbClientParameterResolver.java delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/ExceptionalStmtIT.java delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/FlowControlIT.java delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/GetStatementIT.java delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/HealthCheckIT.java delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/InterceptorIT.java delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/MapperIT.java delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/QueryStatementIT.java delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/ServerHealthCheckIT.java delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/ServerMetricsCheckIT.java delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/SimpleDeleteIT.java delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/SimpleDmlIT.java delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/SimpleGetIT.java delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/SimpleInsertIT.java delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/SimpleQueriesIT.java delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/SimpleUpdateIT.java delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/StatementDmlIT.java delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/TransactionDeleteIT.java delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/TransactionExceptionalStmtIT.java delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/TransactionGetIT.java delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/TransactionInsertIT.java delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/TransactionQueriesIT.java delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/TransactionUpdateIT.java delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/utils/MapperProvider.java delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/utils/RangePoJo.java delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/utils/TestConfig.java delete mode 100644 tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/utils/VerifyData.java delete mode 100644 tests/integration/dbclient/common/src/main/java/module-info.java rename tests/integration/{harness/src/main/resources/META-INF/services/org.junit.jupiter.api.extension.Extension => dbclient/common/src/main/resources/META-INF/services/io.helidon.common.mapper.spi.MapperProvider} (77%) rename tests/integration/dbclient/{app => common}/src/main/resources/META-INF/services/io.helidon.dbclient.spi.DbMapperProvider (80%) create mode 100644 tests/integration/dbclient/common/src/main/resources/db-common.yaml create mode 100644 tests/integration/dbclient/h2/README.md delete mode 100644 tests/integration/dbclient/h2/src/main/java/io/helidon/tests/integration/dbclient/jdbc/H2SetupProvider.java rename etc/pods/pgsql.yaml => tests/integration/dbclient/h2/src/main/resources/db.yaml (60%) rename tests/integration/dbclient/{app/src/main/resources/common.yaml => h2/src/main/resources/logging.properties} (83%) create mode 100644 tests/integration/dbclient/h2/src/main/resources/simplelogger.properties create mode 100644 tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2LocalTest.java create mode 100644 tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2MiscLocalTestIT.java create mode 100644 tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2MiscRemoteTestIT.java create mode 100644 tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2ObservabilityLocalTestIT.java create mode 100644 tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2ObservabilityRemoteTestIT.java create mode 100644 tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2RemoteTest.java create mode 100644 tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2SimpleLocalTestIT.java create mode 100644 tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2SimpleRemoteTestIT.java create mode 100644 tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2StatementLocalTestIT.java create mode 100644 tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2StatementRemoteTestIT.java create mode 100644 tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2TransactionLocalTestIT.java create mode 100644 tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2TransactionRemoteTestIT.java delete mode 100644 tests/integration/dbclient/h2/src/test/resources/h2.yaml create mode 100644 tests/integration/dbclient/mongodb/README.md create mode 100644 tests/integration/dbclient/mongodb/etc/docker/Dockerfile create mode 100755 tests/integration/dbclient/mongodb/etc/docker/entrypoint.sh create mode 100644 tests/integration/dbclient/mongodb/etc/docker/mongodb-org-7.0.repo create mode 100644 tests/integration/dbclient/mongodb/src/main/resources/db.yaml rename tests/integration/{harness/src/main/resources/META-INF/services/org.junit.platform.launcher.TestExecutionListener => dbclient/mongodb/src/main/resources/logging.properties} (83%) create mode 100644 tests/integration/dbclient/mongodb/src/main/resources/simplelogger.properties create mode 100644 tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBLocalTest.java create mode 100644 tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBMiscLocalTestIT.java create mode 100644 tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBMiscRemoteTestIT.java create mode 100644 tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBObservabilityLocalTestIT.java create mode 100644 tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBObservabilityRemoteTestIT.java create mode 100644 tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBRemoteTest.java create mode 100644 tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBSimpleLocalTestIT.java create mode 100644 tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBSimpleRemoteTestIT.java create mode 100644 tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBStatementLocalTestIT.java create mode 100644 tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBStatementRemoteTestIT.java delete mode 100644 tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBSuiteIT.java create mode 100644 tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBTestContainer.java delete mode 100644 tests/integration/dbclient/mongodb/src/test/resources/test.yaml create mode 100644 tests/integration/dbclient/mysql/README.md create mode 100644 tests/integration/dbclient/mysql/pom.xml create mode 100644 tests/integration/dbclient/mysql/src/main/resources/db.yaml create mode 100644 tests/integration/dbclient/mysql/src/main/resources/logging.properties create mode 100644 tests/integration/dbclient/mysql/src/main/resources/simplelogger.properties create mode 100644 tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLLocalTest.java create mode 100644 tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLMiscLocalTestIT.java create mode 100644 tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLMiscRemoteTestIT.java create mode 100644 tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLObservabilityLocalTestIT.java create mode 100644 tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLObservabilityRemoteTestIT.java create mode 100644 tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLRemoteTest.java create mode 100644 tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLSimpleLocalTestIT.java create mode 100644 tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLSimpleRemoteTestIT.java create mode 100644 tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLStatementLocalTestIT.java create mode 100644 tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLStatementRemoteTestIT.java create mode 100644 tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLTestContainer.java create mode 100644 tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLTransactionLocalTestIT.java create mode 100644 tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLTransactionRemoteTestIT.java create mode 100644 tests/integration/dbclient/oracle/README.md create mode 100644 tests/integration/dbclient/oracle/pom.xml create mode 100644 tests/integration/dbclient/oracle/src/main/resources/db.yaml create mode 100644 tests/integration/dbclient/oracle/src/main/resources/logging.properties create mode 100644 tests/integration/dbclient/oracle/src/main/resources/simplelogger.properties create mode 100644 tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleLocalTest.java create mode 100644 tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleMiscLocalTestIT.java create mode 100644 tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleMiscRemoteTestIT.java create mode 100644 tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleObservabilityLocalTestIT.java create mode 100644 tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleObservabilityRemoteTestIT.java create mode 100644 tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleRemoteTest.java create mode 100644 tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleSimpleLocalTestIT.java create mode 100644 tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleSimpleRemoteTestIT.java create mode 100644 tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleStatementLocalTestIT.java create mode 100644 tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleStatementRemoteTestIT.java create mode 100644 tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleTestContainer.java create mode 100644 tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleTransactionLocalTestIT.java create mode 100644 tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleTransactionRemoteTestIT.java create mode 100644 tests/integration/dbclient/parent/pom.xml create mode 100644 tests/integration/dbclient/pgsql/README.md create mode 100644 tests/integration/dbclient/pgsql/etc/docker/Dockerfile create mode 100755 tests/integration/dbclient/pgsql/etc/docker/entrypoint.sh create mode 100644 tests/integration/dbclient/pgsql/pom.xml create mode 100644 tests/integration/dbclient/pgsql/src/main/resources/db.yaml create mode 100644 tests/integration/dbclient/pgsql/src/main/resources/logging.properties create mode 100644 tests/integration/dbclient/pgsql/src/main/resources/simplelogger.properties create mode 100644 tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLLocalTest.java create mode 100644 tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLMiscLocalTestIT.java create mode 100644 tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLMiscRemoteTestIT.java create mode 100644 tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLObservabilityLocalTestIT.java create mode 100644 tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLObservabilityRemoteTestIT.java create mode 100644 tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLRemoteTest.java create mode 100644 tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLSimpleLocalTestIT.java create mode 100644 tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLSimpleRemoteTestIT.java create mode 100644 tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLStatementLocalTestIT.java create mode 100644 tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLStatementRemoteTestIT.java create mode 100644 tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLTestContainer.java create mode 100644 tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLTransactionLocalTestIT.java create mode 100644 tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLTransactionRemoteTestIT.java delete mode 100644 tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/AfterSuite.java delete mode 100644 tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/AppResponse.java delete mode 100644 tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/HelidonProcessRunner.java delete mode 100644 tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/HelidonTestException.java delete mode 100644 tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/JsonValues.java create mode 100644 tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/PathFinder.java create mode 100644 tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/ProcessMonitor.java create mode 100644 tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/ProcessRunner.java create mode 100644 tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/ProcessRunnerExtension.java delete mode 100644 tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/RemoteTestException.java delete mode 100644 tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/SuiteContext.java delete mode 100644 tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/SuiteFinder.java delete mode 100644 tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/SuiteLifeCycle.java delete mode 100644 tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/SuiteParameterResolver.java delete mode 100644 tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/TestClient.java rename tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/{SetUp.java => TestProcess.java} (70%) rename tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/{BeforeSuite.java => TestProcesses.java} (62%) delete mode 100644 tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/TestServiceClient.java create mode 100644 tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/WaitStrategy.java diff --git a/all/pom.xml b/all/pom.xml index 7bf40904ed8..8a423d9567e 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -595,6 +595,10 @@ io.helidon.integrations.db helidon-integrations-db-mysql
        + + io.helidon.integrations.db + helidon-integrations-db-pgsql + io.helidon.integrations.cdi helidon-integrations-cdi-configurable diff --git a/bom/pom.xml b/bom/pom.xml index adddfc941d6..b5532308d1a 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -793,6 +793,11 @@ helidon-integrations-db-mysql ${helidon.version} + + io.helidon.integrations.db + helidon-integrations-db-pgsql + ${helidon.version} + io.helidon.integrations.cdi helidon-integrations-cdi-configurable diff --git a/dependencies/pom.xml b/dependencies/pom.xml index 6694d157097..cc8c1d3e252 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -1304,6 +1304,11 @@ mysql ${version.lib.testcontainers} + + org.testcontainers + jdbc + ${version.lib.testcontainers} + org.testcontainers oracle-xe diff --git a/docs/pom.xml b/docs/pom.xml index c9c3f3d5583..e9f8aa3d2c5 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -81,6 +81,11 @@ ${version.lib.jbatch.container} true + + org.postgresql + postgresql + true + diff --git a/etc/copyright-exclude.txt b/etc/copyright-exclude.txt index 3c4b0e2df76..cf1dcc364f8 100644 --- a/etc/copyright-exclude.txt +++ b/etc/copyright-exclude.txt @@ -67,3 +67,4 @@ src/test/resources/static/classpath/index.html ._java_ ._inject_ service.loader +.repo diff --git a/etc/pods/mysql.yaml b/etc/pods/mysql.yaml deleted file mode 100644 index 40f46b5aa62..00000000000 --- a/etc/pods/mysql.yaml +++ /dev/null @@ -1,35 +0,0 @@ -# -# Copyright (c) 2018, 2020 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. -# - -apiVersion: v1 -kind: Pod -metadata: - name: mysql -spec: - containers: - - name: mysql - image: mysql:8 - ports: - - containerPort: 3306 - env: - - name: MYSQL_USER - value: "user" - - name: MYSQL_PASSWORD - value: "password" - - name: MYSQL_ROOT_PASSWORD - value: "root" - - name: MYSQL_DATABASE - value: "pokemon" diff --git a/etc/pods/vault.yaml b/etc/pods/vault.yaml deleted file mode 100644 index ad21996bc48..00000000000 --- a/etc/pods/vault.yaml +++ /dev/null @@ -1,44 +0,0 @@ -# -# Copyright (c) 2021 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. -# - -apiVersion: v1 -kind: Pod -metadata: - name: vault -spec: - containers: - - name: mysql - image: mysql:8 - imagePullPolicy: "IfNotPresent" - ports: - - containerPort: 3306 - env: - - name: MYSQL_USER - value: "user" - - name: MYSQL_PASSWORD - value: "password" - - name: MYSQL_ROOT_PASSWORD - value: "root" - - name: MYSQL_DATABASE - value: "pokemon" - - name: vault - image: vault:1.7.0 - imagePullPolicy: "IfNotPresent" - ports: - - containerPort: 8200 - env: - - name: VAULT_DEV_ROOT_TOKEN_ID - value: "myroot" \ No newline at end of file diff --git a/tests/integration/dbclient/app/pom.xml b/tests/integration/dbclient/app/pom.xml deleted file mode 100644 index 0b01742c984..00000000000 --- a/tests/integration/dbclient/app/pom.xml +++ /dev/null @@ -1,265 +0,0 @@ - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../../applications/se/pom.xml - - io.helidon.tests.integration.dbclient - helidon-tests-integration-dbclient-app - 4.1.0-SNAPSHOT - Helidon Tests Integration Database Client Application - - - io.helidon.tests.integration.dbclient.app.Main - true - 1.9.3 - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver.observe - helidon-webserver-observe-health - - - io.helidon.webserver.observe - helidon-webserver-observe-metrics - - - io.helidon.config - helidon-config - - - io.helidon.config - helidon-config-yaml - - - io.helidon.logging - helidon-logging-jul - - - io.helidon.dbclient - helidon-dbclient-jdbc - - - io.helidon.dbclient - helidon-dbclient-hikari - - - io.helidon.dbclient - helidon-dbclient-health - - - io.helidon.dbclient - helidon-dbclient-metrics - - - io.helidon.dbclient - helidon-dbclient-metrics-hikari - - - io.helidon.tests.integration.dbclient - helidon-tests-integration-dbclient-common - ${project.version} - - - io.helidon.tests.integration - helidon-tests-integration-harness - ${project.version} - - - org.eclipse.parsson - parsson - - - org.slf4j - slf4j-jdk14 - - - io.helidon.webclient - helidon-webclient - test - - - org.junit.jupiter - junit-jupiter-api - test - - - org.junit.platform - junit-platform-suite-engine - ${version.lib.junit-suite} - test - - - org.hamcrest - hamcrest-all - test - - - - - - src/main/resources - true - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - **/*IT - - - - - org.apache.maven.plugins - maven-failsafe-plugin - - false - methods - 10 - - true - ${app.config} - ${db.user} - ${db.password} - ${db.url} - - - - - test - integration-test - - integration-test - verify - - - - **/*SuiteIT - - - - - - - - - - native-image - - - - org.apache.maven.plugins - maven-failsafe-plugin - - - native - - - - - - - - h2 - - - !db - - - - h2.yaml - test - sa - - jdbc:h2:mem:${db.database};INIT=SET TRACE_LEVEL_FILE=2;DATABASE_TO_UPPER=FALSE - - - - io.helidon.integrations.db - h2 - - - com.h2database - h2 - - - - - mysql - - - db - mysql - - - - - io.helidon.integrations.db - helidon-integrations-db-mysql - ${project.version} - - - com.mysql - mysql-connector-j - - - - - pgsql - - - db - pgsql - - - - - io.helidon.integrations.db - helidon-integrations-db-pgsql - ${project.version} - - - org.postgresql - postgresql - - - - - diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/ErrorHandlerImpl.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/ErrorHandlerImpl.java deleted file mode 100644 index f62cb574ff7..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/ErrorHandlerImpl.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2023 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.tests.integration.dbclient.app; - -import io.helidon.webserver.http.ErrorHandler; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -import static io.helidon.tests.integration.harness.AppResponse.exceptionStatus; - -/** - * Error handler. - */ -class ErrorHandlerImpl implements ErrorHandler { - - /** - * Singleton. - */ - static final ErrorHandler INSTANCE = new ErrorHandlerImpl(); - - private ErrorHandlerImpl() { - } - - @Override - public void handle(ServerRequest req, ServerResponse res, Throwable th) { - th.printStackTrace(); - res.send(exceptionStatus(th)); - } -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/InitService.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/InitService.java deleted file mode 100644 index 9255caf9b96..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/InitService.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app; - -import java.lang.System.Logger.Level; -import java.util.List; -import java.util.Map; - -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbClientException; -import io.helidon.dbclient.DbExecute; -import io.helidon.dbclient.DbTransaction; -import io.helidon.dbclient.health.DbClientHealthCheck; -import io.helidon.health.HealthCheck; -import io.helidon.health.HealthCheckResponse; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.common.model.Type; - -import jakarta.json.Json; -import jakarta.json.JsonObjectBuilder; - -import static io.helidon.tests.integration.harness.AppResponse.okStatus; - -/** - * Service for tests initialization services. - */ -public class InitService implements HttpService { - - private static final System.Logger LOGGER = System.getLogger(InitService.class.getName()); - - private final DbClient dbClient; - private final Config dbConfig; - - /** - * Creates an instance of web resource for tests initialization services. - * - * @param dbClient DbClient instance - * @param dbConfig testing application configuration - */ - InitService(DbClient dbClient, Config dbConfig) { - this.dbClient = dbClient; - this.dbConfig = dbConfig; - } - - @Override - public void routing(HttpRules rules) { - rules - .get("/testPing", this::testPing) - .get("/testHealthCheck", this::testHealthCheck) - .get("/testDropSchema", this::testDropSchema) - .get("/testInitSchema", this::testInitSchema) - .get("/testInitTypes", this::testInitTypes) - .get("/testInitPokemons", this::testInitPokemons) - .get("/testInitPokemonTypes", this::testInitPokemonTypes); - } - - private void testPing(ServerRequest request, ServerResponse response) { - boolean ping = dbConfig.get("test.ping-dml") - .map(c -> c.asBoolean().get()) - .orElse(false); - JsonObjectBuilder data = Json.createObjectBuilder(); - data.add("ping-dml", ping); - response.send(okStatus(data.build())); - } - - private void testHealthCheck(ServerRequest request, ServerResponse response) { - HealthCheck check = DbClientHealthCheck.create( - dbClient, - dbConfig.get("health-check")); - HealthCheckResponse checkResponse = check.call(); - HealthCheckResponse.Status checkState = checkResponse.status(); - JsonObjectBuilder data = Json.createObjectBuilder(); - data.add("state", checkState.name()); - response.send(okStatus(data.build())); - } - - private void testDropSchema(ServerRequest request, ServerResponse response) { - DbExecute exec = dbClient.execute(); - long count = 0; - for (String schema : List.of("poketypes", "pokemons", "types")) { - String statementName = "drop-" + schema; - try { - count += exec.namedDml(statementName); - } catch (DbClientException ex) { - LOGGER.log(Level.DEBUG, () -> String.format( - "Unable to execute statement: %s, %s", - statementName, - ex.getMessage())); - } - } - response.send(okStatus(Json.createValue(count))); - } - - private void testInitSchema(ServerRequest request, ServerResponse response) { - DbExecute exec = dbClient.execute(); - long count = 0; - for (String schema : List.of("types", "pokemons", "poketypes")) { - String statementName = "create-" + schema; - try { - count += exec.namedDml(statementName); - } catch (DbClientException ex) { - LOGGER.log(Level.DEBUG, () -> String.format( - "Unable to execute statement: %s, %s", - statementName, - ex.getMessage())); - } - } - response.send(okStatus(Json.createValue(count))); - } - - private void testInitTypes(ServerRequest request, ServerResponse response) { - DbTransaction tx = dbClient.transaction(); - long count = 0; - for (Map.Entry entry : Type.TYPES.entrySet()) { - count += tx.namedDml("insert-type", entry.getKey(), entry.getValue().name()); - } - tx.commit(); - response.send(okStatus(Json.createValue(count))); - } - - private void testInitPokemons(ServerRequest request, ServerResponse response) { - DbTransaction tx = dbClient.transaction(); - long count = 0; - for (Map.Entry entry : Pokemon.POKEMONS.entrySet()) { - count += tx.namedDml("insert-pokemon", entry.getKey(), entry.getValue().getName()); - } - tx.commit(); - response.send(okStatus(Json.createValue(count))); - } - - private void testInitPokemonTypes(ServerRequest request, ServerResponse response) { - DbTransaction tx = dbClient.transaction(); - long count = 0; - for (Map.Entry entry : Pokemon.POKEMONS.entrySet()) { - Pokemon pokemon = entry.getValue(); - for (Type type : pokemon.getTypes()) { - count += tx.namedDml("insert-poketype", pokemon.getId(), type.id()); - } - } - tx.commit(); - response.send(okStatus(Json.createValue(count))); - } -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/Main.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/Main.java deleted file mode 100644 index 4f6cf0c0ce9..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/Main.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app; - -import java.lang.System.Logger.Level; -import java.util.Map; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbClientException; -import io.helidon.dbclient.DbClientService; -import io.helidon.dbclient.DbStatementType; -import io.helidon.dbclient.health.DbClientHealthCheck; -import io.helidon.dbclient.metrics.DbClientMetrics; -import io.helidon.metrics.api.MetricsFactory; -import io.helidon.tests.integration.dbclient.app.tests.FlowControlService; -import io.helidon.tests.integration.dbclient.app.tests.HealthCheckService; -import io.helidon.tests.integration.dbclient.app.tests.InterceptorService; -import io.helidon.tests.integration.dbclient.app.tests.MapperService; -import io.helidon.tests.integration.dbclient.app.tests.SimpleDeleteService; -import io.helidon.tests.integration.dbclient.app.tests.SimpleGetService; -import io.helidon.tests.integration.dbclient.app.tests.SimpleInsertService; -import io.helidon.tests.integration.dbclient.app.tests.SimpleQueryService; -import io.helidon.tests.integration.dbclient.app.tests.SimpleUpdateService; -import io.helidon.tests.integration.dbclient.app.tests.StatementDmlService; -import io.helidon.tests.integration.dbclient.app.tests.StatementGetService; -import io.helidon.tests.integration.dbclient.app.tests.StatementQueryService; -import io.helidon.tests.integration.dbclient.app.tests.TransactionDeleteService; -import io.helidon.tests.integration.dbclient.app.tests.TransactionGetService; -import io.helidon.tests.integration.dbclient.app.tests.TransactionInsertService; -import io.helidon.tests.integration.dbclient.app.tests.TransactionQueryService; -import io.helidon.tests.integration.dbclient.app.tests.TransactionUpdateService; -import io.helidon.tests.integration.dbclient.app.tools.ExitService; -import io.helidon.tests.integration.harness.RemoteTestException; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.observe.ObserveFeature; -import io.helidon.webserver.observe.health.HealthObserver; - -/** - * Main class. - * Testing application entry point. - */ -public class Main { - - private static final System.Logger LOGGER = System.getLogger(Main.class.getName()); - private static final String CONFIG_PROPERTY_NAME = "app.config"; - private static final String DEFAULT_CONFIG_FILE = "test.yaml"; - - /** - * Start the server. - * - * @param configFile config file - * @return server - */ - public static WebServer startServer(String configFile) { - - Config config = Config.create(ConfigSources.classpath("common.yaml"), - ConfigSources.classpath(configFile)); - Config.global(config); - - Config dbConfig = config.get("db"); - MetricsFactory.getInstance(config.get("metrics")); - - // Client services are added through a service loader - see mongoDB example for explicit services - DbClient dbClient = DbClient.builder(dbConfig) - .addService(DbClientMetrics.counter() - .statementNames( - "select-pokemon-named-arg", - "select-pokemon-order-arg", - "insert-pokemon")) - .addService(DbClientMetrics.timer().statementTypes(DbStatementType.GET)) - .build(); - - HealthObserver health = HealthObserver.builder() - .addCheck(DbClientHealthCheck.builder(dbClient) - .statementName("ping-query") - .build()) - .build(); - - Map statements = dbConfig.get("statements") - .detach() - .asMap() - .get(); - - ExitService exitResource = new ExitService(); - - DbClientService interceptorTestService = new InterceptorService.TestClientService(); - - // Prepare routing for the server - WebServer server = WebServer.builder() - .featuresDiscoverServices(false) - .addFeature(ObserveFeature.builder().addObserver(health).build()) - .routing(routing -> routing - .register("/Init", new InitService(dbClient, dbConfig)) - .register("/Exit", exitResource) - .register("/Verify", new VerifyService(dbClient, config)) - .register("/SimpleGet", new SimpleGetService(dbClient, statements)) - .register("/SimpleQuery", new SimpleQueryService(dbClient, statements)) - .register("/SimpleUpdate", new SimpleUpdateService(dbClient, statements)) - .register("/SimpleInsert", new SimpleInsertService(dbClient, statements)) - .register("/SimpleDelete", new SimpleDeleteService(dbClient, statements)) - .register("/TransactionGet", new TransactionGetService(dbClient, statements)) - .register("/TransactionQueries", new TransactionQueryService(dbClient, statements)) - .register("/TransactionUpdate", new TransactionUpdateService(dbClient, statements)) - .register("/TransactionInsert", new TransactionInsertService(dbClient, statements)) - .register("/TransactionDelete", new TransactionDeleteService(dbClient, statements)) - .register("/StatementDml", new StatementDmlService(dbClient, statements)) - .register("/StatementGet", new StatementGetService(dbClient, statements)) - .register("/StatementQuery", new StatementQueryService(dbClient, statements)) - .register("/FlowControl", new FlowControlService(dbClient, statements)) - .register("/Mapper", new MapperService(dbClient, statements)) - .register("/Interceptor", new InterceptorService( - DbClient.builder(dbConfig) - .addService(interceptorTestService).build(), - statements, - interceptorTestService)) - .register("/HealthCheck", new HealthCheckService(dbClient, dbConfig, statements)) - .error(DbClientException.class, ErrorHandlerImpl.INSTANCE) - .error(RemoteTestException.class, ErrorHandlerImpl.INSTANCE)) - .config(config.get("server")) - .build() - .start(); - - exitResource.setServer(server); - - // Start the server and print some info. - System.out.println("WEB server is up! http://localhost:" + server.port() + "/"); - - return server; - } - - /** - * Main method. - * - * @param args command line arguments - */ - public static void main(String[] args) { - String configFile; - if (args != null && args.length > 0) { - configFile = args[0]; - } else { - configFile = System.getProperty(CONFIG_PROPERTY_NAME, DEFAULT_CONFIG_FILE); - } - LOGGER.log(Level.INFO, () -> String.format("Configuration file: %s", configFile)); - startServer(configFile); - } -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/VerifyService.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/VerifyService.java deleted file mode 100644 index 20dfe368832..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/VerifyService.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app; - -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbExecute; -import io.helidon.tests.integration.dbclient.app.tests.AbstractService; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -import jakarta.json.Json; -import jakarta.json.JsonArrayBuilder; -import jakarta.json.JsonObject; -import jakarta.json.JsonObjectBuilder; - -import static io.helidon.tests.integration.harness.AppResponse.okStatus; - -/** - * Service for test data verification. - */ -public class VerifyService implements HttpService { - - private final DbClient dbClient; - private final Config config; - - VerifyService(DbClient dbClient, Config config) { - this.dbClient = dbClient; - this.config = config; - } - - @Override - public void routing(HttpRules rules) { - rules.get("/getPokemonById", this::getPokemonById) - .get("/getDatabaseType", this::getDatabaseType) - .get("/getConfigParam", this::getConfigParam); - } - - private void getPokemonById(ServerRequest request, ServerResponse response) { - DbExecute exec = dbClient.execute(); - String idStr = AbstractService.queryParam(request, QueryParams.ID); - int id = Integer.parseInt(idStr); - JsonObject jsonObject = exec - .namedGet("get-pokemon-by-id", id) - .map(row -> Json.createObjectBuilder() - .add("name", row.column("name").getString()) - .add("id", row.column("id").getInt()) - .add("types", exec.namedQuery("get-pokemon-types", id) - .map(typeRow -> typeRow.as(JsonObject.class)) - .collect( - Json::createArrayBuilder, - JsonArrayBuilder::add, - JsonArrayBuilder::add) - .build()) - .build()) - .orElse(JsonObject.EMPTY_JSON_OBJECT); - response.send(okStatus(jsonObject)); - } - - private void getDatabaseType(ServerRequest request, ServerResponse response) { - JsonObjectBuilder job = Json.createObjectBuilder(); - job.add("type", dbClient.dbType()); - response.send(okStatus(job.build())); - } - - private void getConfigParam(ServerRequest request, ServerResponse response) { - String name = AbstractService.queryParam(request, QueryParams.NAME); - Config node = config.get(name); - JsonObjectBuilder job = Json.createObjectBuilder(); - if (!node.exists()) { - response.send(okStatus(job.build())); - return; - } - job.add("config", node.as(String.class).get()); - response.send(okStatus(job.build())); - } - -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/dbmapper/DbClientMapperProvider.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/dbmapper/DbClientMapperProvider.java deleted file mode 100644 index 687a3e3d864..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/dbmapper/DbClientMapperProvider.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.dbmapper; - -import java.util.Optional; - -import io.helidon.dbclient.DbMapper; -import io.helidon.dbclient.spi.DbMapperProvider; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.common.model.RangePoJo; - -import jakarta.json.JsonObject; - -/** - * Provides Database Client mappers. - */ -public class DbClientMapperProvider implements DbMapperProvider { - - @Override - public Optional> mapper(Class type) { - if (type.equals(JsonObject.class)) { - return Optional.of((DbMapper)DbRowToJsonObjectMapper.getInstance()); - } else if (type.equals(RangePoJo.class)) { - return Optional.of((DbMapper) RangePoJo.Mapper.INSTANCE); - } else if (type.equals(Pokemon.class)) { - return Optional.of((DbMapper) Pokemon.PokemonMapper.INSTANCE); - } else { - return Optional.empty(); - } - } -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/dbmapper/DbRowToJsonObjectMapper.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/dbmapper/DbRowToJsonObjectMapper.java deleted file mode 100644 index 4aa2702eae6..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/dbmapper/DbRowToJsonObjectMapper.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.dbmapper; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.BiConsumer; - -import io.helidon.dbclient.DbColumn; -import io.helidon.dbclient.DbMapper; -import io.helidon.dbclient.DbRow; - -import jakarta.json.Json; -import jakarta.json.JsonNumber; -import jakarta.json.JsonObject; -import jakarta.json.JsonObjectBuilder; -import jakarta.json.JsonValue; - -// This implementation is limited only to conversions required by jUnit tests. -/** - * Mapper for DbRow to JsonObject conversion. - */ -public class DbRowToJsonObjectMapper implements DbMapper { - - private static final DbRowToJsonObjectMapper INSTANCE = new DbRowToJsonObjectMapper(); - - // Conversion is based on code used in EclipseLink: - // https://github.com/eclipse-ee4j/eclipselink/blob/master/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/helper/ConversionManager.java#L164 - // https://github.com/eclipse-ee4j/eclipselink/blob/master/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/databaseaccess/DatabaseAccessor.java#L1347 - private static final Map, BiConsumer> MAPPERS = new HashMap<>(); - - public static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyy-MM-dd"); - public static final SimpleDateFormat TIME_FORMATTER = new SimpleDateFormat("HH:mm:ss"); - public static final SimpleDateFormat DATE_TIME_FORMATTER = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); - - static { - MAPPERS.put(Byte.class, (job, column) -> job.add(column.name(), column.get(Byte.class).intValue())); - MAPPERS.put(Short.class, (job, column) -> job.add(column.name(), column.get(Short.class).intValue())); - MAPPERS.put(Integer.class, (job, column) -> job.add(column.name(), column.get(Integer.class))); - MAPPERS.put(Long.class, (job, column) -> job.add(column.name(), column.get(Long.class))); - MAPPERS.put(Float.class, (job, column) -> job.add(column.name(), column.get(Float.class).doubleValue())); - MAPPERS.put(Double.class, (job, column) -> job.add(column.name(), column.get(Double.class))); - MAPPERS.put(BigInteger.class, (job, column) -> job.add(column.name(), column.get(BigInteger.class))); - MAPPERS.put(BigDecimal.class, (job, column) -> job.add(column.name(), column.get(BigDecimal.class))); - MAPPERS.put(String.class, (job, column) -> job.add(column.name(), column.get(String.class))); - MAPPERS.put(Character.class, (job, column) -> job.add(column.name(), column.get(Character.class).toString())); - MAPPERS.put(Boolean.class, (job, column) -> job.add(column.name(), column.get(Boolean.class))); - MAPPERS.put(java.sql.Date.class, (job, column) -> job.add(column.name(), DATE_FORMATTER.format(column.as(java.sql.Date.class)))); - MAPPERS.put(java.sql.Time.class, (job, column) -> job.add(column.name(), TIME_FORMATTER.format(column.as(java.sql.Time.class)))); - MAPPERS.put(java.sql.Timestamp.class, (job, column) -> job.add(column.name(), DATE_TIME_FORMATTER.format(column.as(java.sql.Timestamp.class)))); - MAPPERS.put(java.util.Date.class, (job, column) -> job.add(column.name(), DATE_TIME_FORMATTER.format(column.as(java.util.Date.class)))); - } - - static final DbRowToJsonObjectMapper getInstance() { - return INSTANCE; - } - - @Override - public JsonObject read(DbRow dbRow) { - JsonObjectBuilder job = Json.createObjectBuilder(); - dbRow.forEach((dbColumn) -> { - BiConsumer mapper = MAPPERS.get(dbColumn.javaType()); - if (mapper != null) { - mapper.accept(job, dbColumn); - } else { - job.add(dbColumn.name(), dbColumn.get().toString()); - } - }); - return job.build(); - } - - @Override - public Map toNamedParameters(JsonObject value) { - Map params = new HashMap<>(value.size()); - for (Map.Entry entry : value.entrySet()) { - switch(entry.getValue().getValueType()) { - case STRING: - params.put(entry.getKey(), entry.getValue().toString()); - break; - case NUMBER: - JsonNumber numberValue = (JsonNumber)entry.getValue(); - if (numberValue.isIntegral()) { - params.put(entry.getKey(), numberValue.bigIntegerValue()); - } else { - params.put(entry.getKey(), numberValue.bigDecimalValue()); - } - break; - case FALSE: - params.put(entry.getKey(), Boolean.FALSE); - break; - case TRUE: - params.put(entry.getKey(), Boolean.TRUE); - break; - case NULL: - params.put(entry.getKey(), null); - break; - } - } - return params; - } - - @Override - public List toIndexedParameters(JsonObject value) { - List params = new ArrayList<>(value.size()); - for (Map.Entry entry : value.entrySet()) { - switch(entry.getValue().getValueType()) { - case STRING: - params.add(entry.getValue().toString()); - break; - case NUMBER: - JsonNumber numberValue = (JsonNumber)entry.getValue(); - if (numberValue.isIntegral()) { - params.add(numberValue.bigIntegerValue()); - } else { - params.add(numberValue.bigDecimalValue()); - } - break; - case FALSE: - params.add(Boolean.FALSE); - break; - case TRUE: - params.add(Boolean.TRUE); - break; - case NULL: - params.add(null); - break; - } - } - return params; - } - -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/AbstractDeleteService.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/AbstractDeleteService.java deleted file mode 100644 index c3293d7d758..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/AbstractDeleteService.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (c) 2023 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.tests.integration.dbclient.app.tests; - -import java.lang.System.Logger.Level; -import java.util.Map; - -import io.helidon.http.NotFoundException; -import io.helidon.dbclient.DbClient; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; - -import jakarta.json.Json; - -import static io.helidon.tests.integration.harness.AppResponse.okStatus; - -/** - * Base service to test delete statements. - */ -public abstract class AbstractDeleteService extends AbstractService { - - private static final System.Logger LOGGER = System.getLogger(AbstractDeleteService.class.getName()); - - /** - * Creates a new instance. - * - * @param dbClient DbClient instance - * @param statements statements from configuration file - */ - protected AbstractDeleteService(DbClient dbClient, Map statements) { - super(dbClient, statements); - } - - @Override - public void routing(HttpRules rules) { - rules.get("/{testName}", this::executeTest); - } - - private void executeTest(ServerRequest request, ServerResponse response) { - String testName = pathParam(request, "testName"); - int id = Integer.parseInt(queryParam(request, QueryParams.ID)); - LOGGER.log(Level.DEBUG, () -> String.format("Running %s.%s on server", getClass().getSimpleName(), testName)); - long count = switch (testName) { - case "testCreateNamedDeleteStrStrOrderArgs" -> testCreateNamedDeleteStrStrOrderArgs(id); - case "testCreateDmlWithDeleteNamedArgs" -> testCreateDmlWithDeleteNamedArgs(id); - case "testCreateNamedDeleteStrNamedArgs" -> testCreateNamedDeleteStrNamedArgs(id); - case "testCreateNamedDeleteStrOrderArgs" -> testCreateNamedDeleteStrOrderArgs(id); - case "testCreateDeleteNamedArgs" -> testCreateDeleteNamedArgs(id); - case "testCreateDeleteOrderArgs" -> testCreateDeleteOrderArgs(id); - case "testNamedDeleteOrderArgs" -> testNamedDeleteOrderArgs(id); - case "testDeleteOrderArgs" -> testDeleteOrderArgs(id); - case "testCreateNamedDmlWithDeleteStrStrOrderArgs" -> testCreateNamedDmlWithDeleteStrStrOrderArgs(id); - case "testCreateNamedDmlWithDeleteStrNamedArgs" -> testCreateNamedDmlWithDeleteStrNamedArgs(id); - case "testCreateNamedDmlWithDeleteStrOrderArgs" -> testCreateNamedDmlWithDeleteStrOrderArgs(id); - case "testCreateDmlWithDeleteOrderArgs" -> testCreateDmlWithDeleteOrderArgs(id); - case "testNamedDmlWithDeleteOrderArgs" -> testNamedDmlWithDeleteOrderArgs(id); - case "testDmlWithDeleteOrderArgs" -> testDmlWithDeleteOrderArgs(id); - default -> throw new NotFoundException("test not found: " + testName); - }; - response.send(okStatus(Json.createValue(count))); - } - - /** - * Verify {@code createNamedDelete(String, String)} API method with ordered parameters. - * - * @param id parameter - * @return count - */ - protected abstract long testCreateNamedDeleteStrStrOrderArgs(int id); - - /** - * Verify {@code createNamedDelete(String)} API method with named parameters. - * - * @param id parameter - * @return count - */ - protected abstract long testCreateNamedDeleteStrNamedArgs(int id); - - /** - * Verify {@code createNamedDelete(String)} API method with ordered parameters - * - * @param id parameter - * @return count - */ - protected abstract long testCreateNamedDeleteStrOrderArgs(int id); - - /** - * Verify {@code createDelete(String)} API method with named parameters. - * - * @param id parameter - * @return count - */ - protected abstract long testCreateDeleteNamedArgs(int id); - - /** - * Verify {@code createDelete(String)} API method with ordered parameters. - * - * @param id parameter - * @return count - */ - protected abstract long testCreateDeleteOrderArgs(int id); - - /** - * Verify {@code namedDelete(String)} API method with ordered parameters. - * - * @param id parameter - * @return count - */ - protected abstract long testNamedDeleteOrderArgs(int id); - - /** - * Verify {@code delete(String)} API method with ordered parameters. - * - * @param id parameter - * @return count - */ - protected abstract long testDeleteOrderArgs(int id); - - /** - * Verify {@code createNamedDmlStatement(String, String)} API method with delete with ordered parameters. - * - * @param id parameter - * @return count - */ - protected abstract long testCreateNamedDmlWithDeleteStrStrOrderArgs(int id); - - /** - * Verify {@code createNamedDmlStatement(String)} API method with delete with named parameters. - * - * @param id parameter - * @return count - */ - protected abstract long testCreateNamedDmlWithDeleteStrNamedArgs(int id); - - /** - * Verify {@code createNamedDmlStatement(String)} API method with delete with ordered parameters. - * - * @param id parameter - * @return count - */ - protected abstract long testCreateNamedDmlWithDeleteStrOrderArgs(int id); - - /** - * Verify {@code createDmlStatement(String)} API method with delete with named parameters. - * - * @param id parameter - * @return count - */ - protected abstract long testCreateDmlWithDeleteNamedArgs(int id); - - /** - * Verify {@code createDmlStatement(String)} API method with delete with ordered parameters. - * - * @param id parameter - * @return count - */ - protected abstract long testCreateDmlWithDeleteOrderArgs(int id); - - /** - * Verify {@code namedDml(String)} API method with delete with ordered parameters. - * - * @param id parameter - * @return count - */ - protected abstract long testNamedDmlWithDeleteOrderArgs(int id); - - /** - * Verify {@code dml(String)} API method with delete with ordered parameters. - * - * @param id parameter - * @return count - */ - protected abstract long testDmlWithDeleteOrderArgs(int id); -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/AbstractGetService.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/AbstractGetService.java deleted file mode 100644 index 6e0bd7266f4..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/AbstractGetService.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2023 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.tests.integration.dbclient.app.tests; - -import io.helidon.http.NotFoundException; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbRow; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; - -import jakarta.json.JsonObject; - -import java.lang.System.Logger.Level; -import java.util.Map; -import java.util.Optional; - -import static io.helidon.tests.integration.harness.AppResponse.okStatus; - -/** - * Base service to test get statements. - */ -public abstract class AbstractGetService extends AbstractService { - - private static final System.Logger LOGGER = System.getLogger(AbstractGetService.class.getName()); - - /** - * Creates a new instance. - * - * @param dbClient DbClient instance - * @param statements statements from configuration file - */ - public AbstractGetService(DbClient dbClient, Map statements) { - super(dbClient, statements); - } - - @Override - public void routing(HttpRules rules) { - rules.get("/{testName}", this::executeTest); - } - - private void executeTest(ServerRequest request, ServerResponse response) { - String testName = pathParam(request, "testName"); - String name = queryParam(request, QueryParams.NAME); - LOGGER.log(Level.DEBUG, () -> String.format("Running %s.%s on server", getClass().getSimpleName(), testName)); - Optional result = switch (testName) { - case "testCreateNamedGetStrStrNamedArgs" -> testCreateNamedGetStrStrNamedArgs(name); - case "testCreateNamedGetStrNamedArgs" -> testCreateNamedGetStrNamedArgs(name); - case "testCreateNamedGetStrOrderArgs" -> testCreateNamedGetStrOrderArgs(name); - case "testCreateGetNamedArgs" -> testCreateGetNamedArgs(name); - case "testCreateGetOrderArgs" -> testCreateGetOrderArgs(name); - case "testNamedGetStrOrderArgs" -> testNamedGetStrOrderArgs(name); - case "testGetStrOrderArgs" -> testGetStrOrderArgs(name); - default -> throw new NotFoundException("test not found: " + testName); - }; - response.send(okStatus(result.map(row -> row.as(JsonObject.class)) - .orElse(JsonObject.EMPTY_JSON_OBJECT))); - } - - /** - * Verify {@code createNamedGet(String, String)} API method with named parameters. - * - * @param name parameter - * @return row - */ - protected abstract Optional testCreateNamedGetStrStrNamedArgs(String name); - - /** - * Verify {@code createNamedGet(String)} API method with named parameters. - * - * @param name parameter - * @return row - */ - protected abstract Optional testCreateNamedGetStrNamedArgs(String name); - - /** - * Verify {@code createNamedGet(String)} API method with ordered parameters. - * - * @param name parameter - * @return row - */ - protected abstract Optional testCreateNamedGetStrOrderArgs(String name); - - /** - * Verify {@code createGet(String)} API method with named parameters. - * - * @param name parameter - * @return row - */ - protected abstract Optional testCreateGetNamedArgs(String name); - - /** - * Verify {@code createGet(String)} API method with ordered parameters. - * - * @param name parameter - * @return row - */ - protected abstract Optional testCreateGetOrderArgs(String name); - - /** - * Verify {@code namedGet(String)} API method with ordered parameters passed directly to the {@code query} method. - * - * @param name parameter - * @return row - */ - protected abstract Optional testNamedGetStrOrderArgs(String name); - - /** - * Verify {@code get(String)} API method with ordered parameters passed directly to the {@code query} method. - * - * @param name parameter - * @return row - */ - protected abstract Optional testGetStrOrderArgs(String name); - -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/AbstractInsertService.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/AbstractInsertService.java deleted file mode 100644 index 2c1a854cb27..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/AbstractInsertService.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (c) 2023 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.tests.integration.dbclient.app.tests; - -import java.lang.System.Logger.Level; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import io.helidon.http.NotFoundException; -import io.helidon.dbclient.DbClient; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.common.model.Type; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; - -import static io.helidon.tests.integration.dbclient.common.model.Type.TYPES; -import static io.helidon.tests.integration.harness.AppResponse.okStatus; - -/** - * Base service to test insert statements. - */ -public abstract class AbstractInsertService extends AbstractService { - - private static final System.Logger LOGGER = System.getLogger(AbstractInsertService.class.getName()); - private static final Map POKEMON_NAMES = Collections.unmodifiableMap(initNames()); - private static final Map> POKEMON_TYPES = Collections.unmodifiableMap(initTypes()); - - @SuppressWarnings("SpellCheckingInspection") - private static Map initNames() { - Map names = new HashMap<>(); - names.put("testCreateNamedInsertStrStrNamedArgs", "Bulbasaur"); - names.put("testCreateNamedInsertStrNamedArgs", "Ivysaur"); - names.put("testCreateNamedInsertStrOrderArgs", "Venusaur"); - names.put("testCreateInsertNamedArgs", "Magby"); - names.put("testCreateInsertOrderArgs", "Magmar"); - names.put("testNamedInsertOrderArgs", "Rattata"); - names.put("testInsertOrderArgs", "Raticate"); - names.put("testCreateNamedDmlWithInsertStrStrNamedArgs", "Torchic"); - names.put("testCreateNamedDmlWithInsertStrNamedArgs", "Combusken"); - names.put("testCreateNamedDmlWithInsertStrOrderArgs", "Treecko"); - names.put("testCreateDmlWithInsertNamedArgs", "Grovyle"); - names.put("testCreateDmlWithInsertOrderArgs", "Sceptile"); - names.put("testNamedDmlWithInsertOrderArgs", "Snover"); - names.put("testDmlWithInsertOrderArgs", "Abomasnow"); - return names; - } - - @SuppressWarnings("SpellCheckingInspection") - private static Map> initTypes() { - Map> types = new HashMap<>(); - types.put("Bulbasaur", List.of(TYPES.get(4), TYPES.get(12))); - types.put("Ivysaur", List.of(TYPES.get(4), TYPES.get(12))); - types.put("Venusaur", List.of(TYPES.get(4), TYPES.get(12))); - types.put("Magby", List.of(TYPES.get(10))); - types.put("Magmar", List.of(TYPES.get(10))); - types.put("Rattata", List.of(TYPES.get(1))); - types.put("Raticate", List.of(TYPES.get(1))); - types.put("Torchic", List.of(TYPES.get(10))); - types.put("Combusken", List.of(TYPES.get(2), TYPES.get(10))); - types.put("Treecko", List.of(TYPES.get(12))); - types.put("Grovyle", List.of(TYPES.get(12))); - types.put("Sceptile", List.of(TYPES.get(12))); - types.put("Snover", List.of(TYPES.get(12), TYPES.get(15))); - types.put("Abomasnow", List.of(TYPES.get(12), TYPES.get(15))); - return types; - } - - /** - * Create a new instance. - * - * @param dbClient dbclient instance - * @param statements statements - */ - public AbstractInsertService(DbClient dbClient, Map statements) { - super(dbClient, statements); - } - - @Override - public void routing(HttpRules rules) { - rules.get("/{testName}", this::executeTest); - } - - private void executeTest(ServerRequest request, ServerResponse response) { - String testName = pathParam(request, "testName"); - LOGGER.log(Level.DEBUG, () -> String.format("Running %s.%s on server", getClass().getSimpleName(), testName)); - int id = Integer.parseInt(queryParam(request, QueryParams.ID)); - String name = POKEMON_NAMES.get(testName); - long count = switch (testName) { - case "testCreateNamedInsertStrStrNamedArgs" -> testCreateNamedInsertStrStrNamedArgs(id, name); - case "testCreateNamedInsertStrNamedArgs" -> testCreateNamedInsertStrNamedArgs(id, name); - case "testCreateNamedInsertStrOrderArgs" -> testCreateNamedInsertStrOrderArgs(id, name); - case "testCreateInsertNamedArgs" -> testCreateInsertNamedArgs(id, name); - case "testCreateInsertOrderArgs" -> testCreateInsertOrderArgs(id, name); - case "testNamedInsertOrderArgs" -> testNamedInsertOrderArgs(id, name); - case "testInsertOrderArgs" -> testInsertOrderArgs(id, name); - case "testCreateNamedDmlWithInsertStrStrNamedArgs" -> testCreateNamedDmlWithInsertStrStrNamedArgs(id, name); - case "testCreateNamedDmlWithInsertStrNamedArgs" -> testCreateNamedDmlWithInsertStrNamedArgs(id, name); - case "testCreateNamedDmlWithInsertStrOrderArgs" -> testCreateNamedDmlWithInsertStrOrderArgs(id, name); - case "testCreateDmlWithInsertNamedArgs" -> testCreateDmlWithInsertNamedArgs(id, name); - case "testCreateDmlWithInsertOrderArgs" -> testCreateDmlWithInsertOrderArgs(id, name); - case "testNamedDmlWithInsertOrderArgs" -> testNamedDmlWithInsertOrderArgs(id, name); - case "testDmlWithInsertOrderArgs" -> testDmlWithInsertOrderArgs(id, name); - default -> throw new NotFoundException("test not found: " + testName); - }; - Pokemon pokemon = new Pokemon(id, name, POKEMON_TYPES.get(name)); - response.send(okStatus(pokemon.toJsonObject())); - } - - /** - * Verify {@code createNamedInsert(String, String)} API method with named parameters. - * - * @param id parameter - * @param name parameter - * @return count - */ - protected abstract long testCreateNamedInsertStrStrNamedArgs(int id, String name); - - /** - * Verify {@code createNamedInsert(String)} API method with named parameters. - * - * @param id parameter - * @param name parameter - * @return count - */ - protected abstract long testCreateNamedInsertStrNamedArgs(int id, String name); - - /** - * Verify {@code createNamedInsert(String)} API method with ordered parameters. - * - * @param id parameter - * @param name parameter - * @return count - */ - protected abstract long testCreateNamedInsertStrOrderArgs(int id, String name); - - /** - * Verify {@code createInsert(String)} API method with named parameters. - * - * @param id parameter - * @param name parameter - */ - protected abstract long testCreateInsertNamedArgs(int id, String name); - - /** - * Verify {@code createInsert(String)} API method with ordered parameters. - * - * @param id parameter - * @param name parameter - * @return count - */ - protected abstract long testCreateInsertOrderArgs(int id, String name); - - /** - * Verify {@code namedInsert(String)} API method with ordered parameters passed directly to the {@code insert} method. - * - * @param id parameter - * @param name parameter - * @return count - */ - protected abstract long testNamedInsertOrderArgs(int id, String name); - - /** - * Verify {@code insert(String)} API method with ordered parameters passed directly to the {@code insert} method. - * - * @param id parameter - * @param name parameter - * @return count - */ - protected abstract long testInsertOrderArgs(int id, String name); - - /** - * Verify {@code createNamedDmlStatement(String, String)} API method with insert with named parameters. - * - * @param id parameter - * @param name parameter - * @return count - */ - protected abstract long testCreateNamedDmlWithInsertStrStrNamedArgs(int id, String name); - - /** - * Verify {@code createNamedDmlStatement(String)} API method with insert with named parameters. - * - * @param id parameter - * @param name parameter - * @return count - */ - protected abstract long testCreateNamedDmlWithInsertStrNamedArgs(int id, String name); - - /** - * Verify {@code createNamedDmlStatement(String)} API method with insert with ordered parameters. - * - * @param id parameter - * @param name parameter - * @return count - */ - protected abstract long testCreateNamedDmlWithInsertStrOrderArgs(int id, String name); - - /** - * Verify {@code createDmlStatement(String)} API method with insert with named parameters. - * - * @param id parameter - * @param name parameter - * @return count - */ - protected abstract long testCreateDmlWithInsertNamedArgs(int id, String name); - - /** - * Verify {@code createDmlStatement(String)} API method with insert with ordered parameters. - * - * @param id parameter - * @param name parameter - * @return count - */ - protected abstract long testCreateDmlWithInsertOrderArgs(int id, String name); - - /** - * Verify {@code namedDml(String)} API method with insert with ordered parameters passed directly - * - * @param id parameter - * @param name parameter - * @return count - */ - protected abstract long testNamedDmlWithInsertOrderArgs(int id, String name); - - /** - * Verify {@code dml(String)} API method with insert with ordered parameters passed directly - * - * @param id parameter - * @param name parameter - * @return count - */ - protected abstract long testDmlWithInsertOrderArgs(int id, String name); -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/AbstractQueryService.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/AbstractQueryService.java deleted file mode 100644 index 8b80426613a..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/AbstractQueryService.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2023 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.tests.integration.dbclient.app.tests; - -import java.lang.System.Logger.Level; -import java.util.List; -import java.util.Map; - -import io.helidon.http.NotFoundException; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbRow; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; - -import jakarta.json.Json; -import jakarta.json.JsonArray; -import jakarta.json.JsonArrayBuilder; -import jakarta.json.JsonObject; - -import static io.helidon.tests.integration.harness.AppResponse.okStatus; - -/** - * Base service to test query statements. - */ -public abstract class AbstractQueryService extends AbstractService { - - private static final System.Logger LOGGER = System.getLogger(AbstractQueryService.class.getName()); - - /** - * Create a new instance. - * - * @param dbClient dbclient - * @param statements statements - */ - public AbstractQueryService(DbClient dbClient, Map statements) { - super(dbClient, statements); - } - - @Override - public void routing(HttpRules rules) { - rules.get("/{testName}", this::executeTest); - } - - private void executeTest(ServerRequest request, ServerResponse response) { - String testName = pathParam(request, "testName"); - String name = queryParam(request, QueryParams.NAME); - LOGGER.log(Level.DEBUG, () -> String.format("Running %s.%s on server", - getClass().getSimpleName(), testName)); - List result = switch (testName) { - case "testCreateNamedQueryStrStrOrderArgs" -> testCreateNamedQueryStrStrOrderArgs(name); - case "testCreateNamedQueryStrNamedArgs" -> testCreateNamedQueryStrNamedArgs(name); - case "testCreateNamedQueryStrOrderArgs" -> testCreateNamedQueryStrOrderArgs(name); - case "testCreateQueryNamedArgs" -> testCreateQueryNamedArgs(name); - case "testCreateQueryOrderArgs" -> testCreateQueryOrderArgs(name); - case "testNamedQueryOrderArgs" -> testNamedQueryOrderArgs(name); - case "testQueryOrderArgs" -> testQueryOrderArgs(name); - default -> throw new NotFoundException("test not found: " + testName); - }; - JsonArray jsonArray = result.stream() - .map(row -> row.as(JsonObject.class)) - .collect(Json::createArrayBuilder, JsonArrayBuilder::add, JsonArrayBuilder::add) - .build(); - response.send(okStatus(jsonArray)); - } - - /** - * Verify {@code createNamedQuery(String, String)} API method with ordered - * - * @param name parameter - * @return rows - */ - protected abstract List testCreateNamedQueryStrStrOrderArgs(String name); - - /** - * Verify {@code createNamedQuery(String)} API method with named parameters. - * - * @param name parameter - * @return rows - */ - protected abstract List testCreateNamedQueryStrNamedArgs(String name); - - /** - * Verify {@code createNamedQuery(String)} API method with ordered - * - * @param name parameter - * @return rows - */ - protected abstract List testCreateNamedQueryStrOrderArgs(String name); - - /** - * Verify {@code createQuery(String)} API method with named parameters. - * - * @param name parameter - * @return rows - */ - protected abstract List testCreateQueryNamedArgs(String name); - - /** - * Verify {@code createQuery(String)} API method with ordered parameters. - * - * @param name parameter - * @return rows - */ - protected abstract List testCreateQueryOrderArgs(String name); - - /** - * Verify {@code namedQuery(String)} API method with ordered parameters - * - * @param name parameter - * @return rows - */ - protected abstract List testNamedQueryOrderArgs(String name); - - /** - * Verify {@code query(String)} API method with ordered parameters passed - * - * @param name parameter - * @return rows - */ - protected abstract List testQueryOrderArgs(String name); -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/AbstractService.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/AbstractService.java deleted file mode 100644 index df36d53ad6f..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/AbstractService.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.util.Map; - -import io.helidon.dbclient.DbClient; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.tests.integration.harness.RemoteTestException; - -/** - * Common web service code for testing application. - */ -public abstract class AbstractService implements HttpService { - - private final DbClient dbClient; - private final Map statements; - - /** - * Creates an instance of common web service code for testing application. - * - * @param dbClient DbClient instance - * @param statements statements from configuration file - */ - public AbstractService(DbClient dbClient, Map statements) { - this.dbClient = dbClient; - this.statements = statements; - } - - /** - * Returns stored DbClient instance. - * - * @return DbClient instance - */ - public DbClient dbClient() { - return dbClient; - } - - /** - * Returns stored statement from configuration file. - * - * @param name statement configuration property name - * @return statement from configuration file - */ - public String statement(String name) { - return statements.get(name); - } - - /** - * Retrieve HTTP query parameter value from request. - * - * @param request HTTP request context - * @param name query parameter name - * @return query parameter value - * @throws RemoteTestException when no parameter with given name exists in request - */ - public static String queryParam(ServerRequest request, String name) { - return request.query().first(name) - .orElseThrow(() -> new RemoteTestException("Query parameter %s is missing.", name)); - } - - /** - * Retrieve HTTP path parameter value from request. - * - * @param request HTTP request context - * @param name path parameter name - * @return path parameter value - * @throws RemoteTestException when no parameter with given name exists in request - */ - public static String pathParam(ServerRequest request, String name) { - return request.path().pathParameters().first(name) - .orElseThrow(() -> new RemoteTestException("Path parameter %s is missing.", name)); - } -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/AbstractUpdateService.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/AbstractUpdateService.java deleted file mode 100644 index 5bdef190979..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/AbstractUpdateService.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (c) 2023 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.tests.integration.dbclient.app.tests; - -import java.lang.System.Logger.Level; -import java.util.Map; - -import io.helidon.http.NotFoundException; -import io.helidon.dbclient.DbClient; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; - -import jakarta.json.Json; - -import static io.helidon.tests.integration.harness.AppResponse.okStatus; - -/** - * Base service to test update statements. - */ -public abstract class AbstractUpdateService extends AbstractService { - - private static final System.Logger LOGGER = System.getLogger(AbstractUpdateService.class.getName()); - - /** - * Create a new instance. - * - * @param dbClient dbclient - * @param statements statements - */ - public AbstractUpdateService(DbClient dbClient, Map statements) { - super(dbClient, statements); - } - - @Override - public void routing(HttpRules rules) { - rules.get("/{testName}", this::executeTest); - } - - private void executeTest(ServerRequest request, ServerResponse response) { - String testName = pathParam(request, "testName"); - int id = Integer.parseInt(queryParam(request, QueryParams.ID)); - String name = queryParam(request, QueryParams.NAME); - LOGGER.log(Level.DEBUG, () -> String.format("Running %s.%s on server", getClass().getSimpleName(), testName)); - long count = switch (testName) { - case "testCreateNamedUpdateStrStrNamedArgs" -> testCreateNamedUpdateStrStrNamedArgs(id, name); - case "testCreateNamedUpdateStrNamedArgs" -> testCreateNamedUpdateStrNamedArgs(id, name); - case "testCreateNamedUpdateStrOrderArgs" -> testCreateNamedUpdateStrOrderArgs(id, name); - case "testCreateUpdateNamedArgs" -> testCreateUpdateNamedArgs(id, name); - case "testCreateUpdateOrderArgs" -> testCreateUpdateOrderArgs(id, name); - case "testNamedUpdateNamedArgs" -> testNamedUpdateNamedArgs(id, name); - case "testUpdateOrderArgs" -> testUpdateOrderArgs(id, name); - case "testCreateNamedDmlWithUpdateStrStrNamedArgs" -> testCreateNamedDmlWithUpdateStrStrNamedArgs(id, name); - case "testCreateNamedDmlWithUpdateStrNamedArgs" -> testCreateNamedDmlWithUpdateStrNamedArgs(id, name); - case "testCreateNamedDmlWithUpdateStrOrderArgs" -> testCreateNamedDmlWithUpdateStrOrderArgs(id, name); - case "testCreateDmlWithUpdateNamedArgs" -> testCreateDmlWithUpdateNamedArgs(id, name); - case "testCreateDmlWithUpdateOrderArgs" -> testCreateDmlWithUpdateOrderArgs(id, name); - case "testNamedDmlWithUpdateOrderArgs" -> testNamedDmlWithUpdateOrderArgs(id, name); - case "testDmlWithUpdateOrderArgs" -> testDmlWithUpdateOrderArgs(id, name); - default -> throw new NotFoundException("test not found: " + testName); - }; - response.send(okStatus(Json.createValue(count))); - } - - /** - * Verify {@code createNamedUpdate(String, String)} API method with ordered parameters. - * - * @param id parameter - * @param name parameter - * @return count - */ - protected abstract long testCreateNamedUpdateStrStrNamedArgs(int id, String name); - - /** - * Verify {@code createNamedUpdate(String)} API method with named parameters. - * - * @param id parameter - * @param name parameter - * @return count - */ - protected abstract long testCreateNamedUpdateStrNamedArgs(int id, String name); - - /** - * Verify {@code createNamedUpdate(String)} API method with ordered parameters. - * - * @param id parameter - * @param name parameter - * @return count - */ - protected abstract long testCreateNamedUpdateStrOrderArgs(int id, String name); - - /** - * Verify {@code createUpdate(String)} API method with named parameters. - * - * @param id parameter - * @param name parameter - * @return count - */ - protected abstract long testCreateUpdateNamedArgs(int id, String name); - - /** - * Verify {@code createUpdate(String)} API method with ordered parameters. - * - * @param id parameter - * @param name parameter - * @return count - */ - protected abstract long testCreateUpdateOrderArgs(int id, String name); - - /** - * Verify {@code namedUpdate(String)} API method with ordered parameters passed directly to the - * {@code namedQuery} method. - * - * @param id parameter - * @param name parameter - * @return count - */ - protected abstract long testNamedUpdateNamedArgs(int id, String name); - - /** - * Verify {@code update(String)} API method with ordered parameters passed directly to the {@code query} method. - * - * @param id parameter - * @param name parameter - * @return count - */ - protected abstract long testUpdateOrderArgs(int id, String name); - - /** - * Verify {@code createNamedDmlStatement(String, String)} API method with update with named parameters. - * - * @param id parameter - * @param name parameter - * @return count - */ - protected abstract long testCreateNamedDmlWithUpdateStrStrNamedArgs(int id, String name); - - /** - * Verify {@code createNamedDmlStatement(String)} API method with update with named parameters. - * - * @param id parameter - * @param name parameter - * @return count - */ - protected abstract long testCreateNamedDmlWithUpdateStrNamedArgs(int id, String name); - - /** - * Verify {@code createNamedDmlStatement(String)} API method with update with ordered parameters. - * - * @param id parameter - * @param name parameter - * @return count - */ - protected abstract long testCreateNamedDmlWithUpdateStrOrderArgs(int id, String name); - - /** - * Verify {@code createDmlStatement(String)} API method with update with named parameters. - * - * @param id parameter - * @param name parameter - * @return count - */ - protected abstract long testCreateDmlWithUpdateNamedArgs(int id, String name); - - /** - * Verify {@code createDmlStatement(String)} API method with update with ordered parameters. - * - * @param id parameter - * @param name parameter - * @return count - */ - protected abstract long testCreateDmlWithUpdateOrderArgs(int id, String name); - - /** - * Verify {@code namedDml(String)} API method with update with ordered parameters passed directly. - * - * @param id parameter - * @param name parameter - * @return count - */ - protected abstract long testNamedDmlWithUpdateOrderArgs(int id, String name); - - /** - * Verify {@code dml(String)} API method with update with ordered parameters passed directly. - * - * @param id parameter - * @param name parameter - * @return count - */ - protected abstract long testDmlWithUpdateOrderArgs(int id, String name); - -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/FlowControlService.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/FlowControlService.java deleted file mode 100644 index c98f6724d3b..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/FlowControlService.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.lang.System.Logger.Level; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; - -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbRow; -import io.helidon.tests.integration.dbclient.common.model.Type; -import io.helidon.tests.integration.harness.RemoteTestException; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -import jakarta.json.Json; -import jakarta.json.JsonObject; -import jakarta.json.JsonObjectBuilder; - -import static io.helidon.tests.integration.harness.AppResponse.okStatus; - -/** - * Service to test proper flow control handling in query processing. - */ -public class FlowControlService extends AbstractService { - - /** - * Local logger instance. - */ - private static final System.Logger LOGGER = System.getLogger(FlowControlService.class.getName()); - - /** - * Creates an instance of web resource to test proper flow control handling in query processing. - * - * @param dbClient DbClient instance - * @param statements statements from configuration file - */ - public FlowControlService(DbClient dbClient, Map statements) { - super(dbClient, statements); - } - - @Override - public void routing(HttpRules rules) { - rules.get("/testSourceData", this::testSourceData) - .get("/testFlowControl", this::testFlowControl); - } - - // Source data verification test. - // Testing code is blocking, so it's running in a separate thread. - private void testSourceData(ServerRequest request, ServerResponse response) { - LOGGER.log(Level.DEBUG, "Running FlowControlService.testSourceData on server"); - Stream rows = dbClient().execute().namedQuery("select-types"); - if (rows == null) { - throw new RemoteTestException("Rows value is null."); - } - List list = rows.toList(); - if (list.isEmpty()) { - throw new RemoteTestException("Rows list is empty."); - } - if (list.size() != 18) { - throw new RemoteTestException("Rows list size shall be 18."); - } - for (DbRow row : list) { - Integer id = row.column(1).get(Integer.class); - String name = row.column(2).get(String.class); - Type type = new Type(id, name); - if (!Type.TYPES.get(id).name().equals(name)) { - throw new RemoteTestException("Expected type name \"%s\", but got \"%s\".", - Type.TYPES.get(id).name(), - name); - } - LOGGER.log(Level.DEBUG, type::toString); - } - response.send(okStatus(JsonObject.EMPTY_JSON_OBJECT)); - } - - // Flow control test. - // Testing code is blocking, so it's running in a separate thread. - private void testFlowControl(ServerRequest request, ServerResponse response) { - LOGGER.log(Level.DEBUG, "Running FlowControlService.testFlowControl on server"); - long count = dbClient().execute().namedQuery("select-types").count(); - LOGGER.log(Level.DEBUG, "Sending OK response."); - JsonObjectBuilder job = Json.createObjectBuilder(); - job.add("total", count); - response.send(okStatus(job.build())); - } -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/HealthCheckService.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/HealthCheckService.java deleted file mode 100644 index a8e08d3ca6d..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/HealthCheckService.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.lang.System.Logger.Level; -import java.util.Map; - -import io.helidon.config.Config; -import io.helidon.health.HealthCheck; -import io.helidon.health.HealthCheckResponse; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.health.DbClientHealthCheck; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; -import io.helidon.tests.integration.harness.AppResponse; -import io.helidon.tests.integration.harness.RemoteTestException; - -import jakarta.json.Json; -import jakarta.json.JsonObjectBuilder; - -/** - * Service to verify that health check works. - */ -public class HealthCheckService extends AbstractService { - - private static final System.Logger LOGGER = System.getLogger(HealthCheckService.class.getName()); - - private final Config dbConfig; - - /** - * Creates an instance of web resource to verify that health check works. - * - * @param dbClient DbClient instance - * @param dbConfig testing application configuration - * @param statements statements from configuration file - */ - public HealthCheckService(DbClient dbClient, Config dbConfig, Map statements) { - super(dbClient, statements); - this.dbConfig = dbConfig; - } - - @Override - public void routing(HttpRules rules) { - rules - .get("/testHealthCheck", this::testHealthCheck) - .get("/testHealthCheckWithName", this::testHealthCheckWithName) - .get("/testHealthCheckWithCustomNamedDML", this::testHealthCheckWithCustomNamedDML) - .get("/testHealthCheckWithCustomDML", this::testHealthCheckWithCustomDML) - .get("/testHealthCheckWithCustomNamedQuery", this::testHealthCheckWithCustomNamedQuery) - .get("/testHealthCheckWithCustomQuery", this::testHealthCheckWithCustomQuery); - } - - private void executeTest(ServerResponse response, String testName, HealthCheck check) { - LOGGER.log(Level.DEBUG, () -> String.format("Running HealthCheckService.%s on server", testName)); - JsonObjectBuilder job = Json.createObjectBuilder(); - HealthCheckResponse hcResponse = check.call(); - HealthCheckResponse.Status state = hcResponse.status(); - job.add("name", check.name()); - job.add("status", state.name()); - response.send(AppResponse.okStatus(job.build())); - } - - // Verify health check implementation with default settings. - private void testHealthCheck(ServerRequest request, ServerResponse response) { - executeTest(response, "testHealthCheck", - DbClientHealthCheck.create( - dbClient(), - dbConfig.get("health-check"))); - } - - // Verify health check implementation with builder and custom name. - private void testHealthCheckWithName(ServerRequest request, ServerResponse response) { - String name = queryParam(request, QueryParams.NAME); - executeTest(response, "testHealthCheckWithName", - DbClientHealthCheck.builder(dbClient()) - .config(dbConfig.get("health-check")) - .name(name) - .build()); - } - - // Verify health check implementation using custom DML named statement. - private void testHealthCheckWithCustomNamedDML(ServerRequest request, ServerResponse response) { - Config cfgStatement = dbConfig.get("statements.ping-dml"); - if (!cfgStatement.exists()) { - throw new RemoteTestException("Missing statements.ping-dml configuration parameter."); - } - executeTest(response, "testHealthCheckWithCustomNamedDML", - DbClientHealthCheck.builder(dbClient()) - .dml() - .statementName("ping-dml") - .build()); - } - - // Verify health check implementation using custom DML statement. - private void testHealthCheckWithCustomDML(ServerRequest request, ServerResponse response) { - Config cfgStatement = dbConfig.get("statements.ping-dml"); - if (!cfgStatement.exists()) { - throw new RemoteTestException("Missing statements.ping-dml configuration parameter."); - } - executeTest(response, "testHealthCheckWithCustomDML", - DbClientHealthCheck.builder(dbClient()) - .dml() - .statement(cfgStatement.as(String.class).get()) - .build()); - } - - // Verify health check implementation using custom query named statement. - private void testHealthCheckWithCustomNamedQuery(ServerRequest request, ServerResponse response) { - Config cfgStatement = dbConfig.get("statements.ping-query"); - if (!cfgStatement.exists()) { - throw new RemoteTestException("Missing statements.ping-query configuration parameter."); - } - executeTest(response, "testHealthCheckWithCustomNamedQuery", - DbClientHealthCheck.builder(dbClient()) - .query() - .statementName("ping-query") - .build()); - } - - // Verify health check implementation using custom query statement. - private void testHealthCheckWithCustomQuery(ServerRequest request, ServerResponse response) { - Config cfgStatement = dbConfig.get("statements.ping-query"); - if (!cfgStatement.exists()) { - throw new RemoteTestException("Missing statements.ping-query configuration parameter."); - } - executeTest(response, "testHealthCheckWithCustomQuery", - DbClientHealthCheck.builder(dbClient()) - .query() - .statement(cfgStatement.as(String.class).get()) - .build()); - } -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/InterceptorService.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/InterceptorService.java deleted file mode 100644 index 68fe774d516..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/InterceptorService.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.util.Map; - -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbClientService; -import io.helidon.dbclient.DbClientServiceContext; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.harness.AppResponse; -import io.helidon.tests.integration.harness.RemoteTestException; - -import jakarta.json.Json; -import jakarta.json.JsonArrayBuilder; -import jakarta.json.JsonObject; - -/** - * Service to verify services handling. - */ -public class InterceptorService extends AbstractService { - - private final DbClientService interceptor; - - /** - * Creates an instance of web resource to verify services handling. - * - * @param dbClient DbClient instance - * @param statements statements from configuration file - * @param interceptor DbClientService interceptor instance used in test - */ - public InterceptorService(DbClient dbClient, Map statements, DbClientService interceptor) { - super(dbClient, statements); - this.interceptor = interceptor; - } - - /** - * Test db service. - */ - public static final class TestClientService implements DbClientService { - - private boolean called; - - /** - * Create a new instance. - */ - public TestClientService() { - this.called = false; - } - - @Override - public DbClientServiceContext statement(DbClientServiceContext context) { - this.called = true; - return context; - } - } - - @Override - public void routing(HttpRules rules) { - rules.get("/testStatementInterceptor", this::testStatementInterceptor); - } - - // Check that statement interceptor was called before statement execution. - private void testStatementInterceptor(ServerRequest request, ServerResponse response) { - JsonArrayBuilder jab = dbClient().execute().createNamedQuery("select-pokemon-named-arg") - .addParam("name", Pokemon.POKEMONS.get(6).getName()) - .execute() - .map(row -> row.as(JsonObject.class)) - .collect(Json::createArrayBuilder, JsonArrayBuilder::add, JsonArrayBuilder::addAll); - if (((TestClientService) interceptor).called) { - response.send(AppResponse.okStatus(jab.build())); - } else { - throw new RemoteTestException("Interceptor service was not called"); - } - } -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/MapperService.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/MapperService.java deleted file mode 100644 index f6ca23e109a..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/MapperService.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.util.Map; -import java.util.Optional; -import java.util.function.Function; -import java.util.stream.Stream; - -import io.helidon.http.NotFoundException; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbRow; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; - -import jakarta.json.Json; -import jakarta.json.JsonArray; -import jakarta.json.JsonArrayBuilder; -import jakarta.json.JsonObject; - -import static io.helidon.tests.integration.dbclient.common.model.Type.TYPES; -import static io.helidon.tests.integration.harness.AppResponse.okStatus; - -/** - * Service to test mapping interface. - */ -public class MapperService extends AbstractService { - - private static final System.Logger LOGGER = System.getLogger(MapperService.class.getName()); - - /** - * Create a new instance. - * - * @param dbClient dbclient - * @param statements statements - */ - public MapperService(DbClient dbClient, Map statements) { - super(dbClient, statements); - } - - @Override - public void routing(HttpRules rules) { - rules.get("/{testName}", this::executeTest); - } - - private void executeTest(ServerRequest req, ServerResponse res) { - String testName = pathParam(req, "testName"); - LOGGER.log(System.Logger.Level.DEBUG, () -> String.format("Running %s.%s on server", getClass().getSimpleName(), testName)); - switch (testName) { - case "testInsertWithOrderMapping" -> execInsert(req, res, this::testInsertWithOrderMapping); - case "testInsertWithNamedMapping" -> execInsert(req, res, this::testInsertWithNamedMapping); - case "testUpdateWithOrderMapping" -> execUpdate(req, res, this::testUpdateWithOrderMapping); - case "testUpdateWithNamedMapping" -> execUpdate(req, res, this::testUpdateWithNamedMapping); - case "testDeleteWithOrderMapping" -> execDelete(req, res, this::testDeleteWithOrderMapping); - case "testDeleteWithNamedMapping" -> execDelete(req, res, this::testDeleteWithNamedMapping); - case "testQueryWithMapping" -> execQueryMapping(req, res, this::testQueryWithMapping); - case "testGetWithMapping" -> execGetMapping(req, res, this::testGetWithMapping); - default -> throw new NotFoundException("test not found: " + testName); - } - } - - private void execInsert(ServerRequest req, ServerResponse res, Function test) { - int id = Integer.parseInt(queryParam(req, QueryParams.ID)); - Pokemon pokemon = test.apply(id); - res.send(okStatus(pokemon.toJsonObject())); - } - - private void execUpdate(ServerRequest req, ServerResponse res, Function test) { - String name = queryParam(req, QueryParams.NAME); - int id = Integer.parseInt(queryParam(req, QueryParams.ID)); - Pokemon srcPokemon = Pokemon.POKEMONS.get(id); - Pokemon updatedPokemon = new Pokemon(id, name, srcPokemon.getTypesArray()); - long count = test.apply(updatedPokemon); - res.send(okStatus(Json.createValue(count))); - } - - private void execDelete(ServerRequest req, ServerResponse res, Function test) { - int id = Integer.parseInt(queryParam(req, QueryParams.ID)); - Pokemon pokemon = Pokemon.POKEMONS.get(id); - long count = test.apply(pokemon); - res.send(okStatus(Json.createValue(count))); - } - - private void execGetMapping(ServerRequest req, ServerResponse res, Function> test) { - String name = queryParam(req, QueryParams.NAME); - JsonObject jsonObject = test.apply(name) - .map(row -> row.as(Pokemon.class).toJsonObject()) - .orElse(JsonObject.EMPTY_JSON_OBJECT); - res.send(okStatus(jsonObject)); - } - - private void execQueryMapping(ServerRequest req, ServerResponse res, Function> test) { - String name = queryParam(req, QueryParams.NAME); - JsonArray jsonArray = test.apply(name) - .map(row -> row.as(Pokemon.class).toJsonObject()) - .collect(Json::createArrayBuilder, JsonArrayBuilder::add, JsonArrayBuilder::add) - .build(); - res.send(okStatus(jsonArray)); - } - - /** - * Verify insertion using indexed mapping. - * - * @param id parameter - * @return pokemon - */ - private Pokemon testInsertWithOrderMapping(int id) { - Pokemon pokemon = new Pokemon(id, "Articuno", Pokemon.typesList(TYPES.get(3), TYPES.get(15))); - dbClient().execute() - .createNamedInsert("insert-pokemon-order-arg-rev") - .indexedParam(pokemon) - .execute(); - return pokemon; - } - - /** - * Verify insertion using named mapping. - * - * @param id parameter - * @return pokemon - */ - private Pokemon testInsertWithNamedMapping(int id) { - Pokemon pokemon = new Pokemon(id, "Zapdos", Pokemon.typesList(TYPES.get(3), TYPES.get(13))); - dbClient().execute() - .createNamedInsert("insert-pokemon-named-arg") - .namedParam(pokemon) - .execute(); - return pokemon; - } - - /** - * Verify update using indexed mapping. - * - * @param pokemon pokemon - * @return count - */ - private long testUpdateWithOrderMapping(Pokemon pokemon) { - return dbClient().execute() - .createNamedUpdate("update-pokemon-order-arg") - .indexedParam(pokemon) - .execute(); - } - - /** - * Verify update using named mapping. - * - * @param pokemon pokemon - * @return count - */ - private long testUpdateWithNamedMapping(Pokemon pokemon) { - return dbClient().execute() - .createNamedUpdate("update-pokemon-named-arg") - .namedParam(pokemon) - .execute(); - } - - /** - * Verify delete using indexed mapping. - * - * @param pokemon pokemon - * @return count - */ - private long testDeleteWithOrderMapping(Pokemon pokemon) { - return dbClient().execute() - .createNamedDelete("delete-pokemon-full-order-arg") - .indexedParam(pokemon) - .execute(); - } - - /** - * Verify delete using named mapping. - * - * @param pokemon pokemon - * @return count - */ - private long testDeleteWithNamedMapping(Pokemon pokemon) { - return dbClient().execute() - .createNamedDelete("delete-pokemon-full-named-arg") - .namedParam(pokemon) - .execute(); - } - - /** - * Verify query as a result using mapping. - * - * @param name parameter - * @return rows - */ - private Stream testQueryWithMapping(String name) { - return dbClient().execute() - .createNamedQuery("select-pokemon-named-arg") - .addParam("name", name) - .execute(); - } - - /** - * Verify get as a result using mapping. - * - * @param name parameter - * @return row - */ - private Optional testGetWithMapping(String name) { - return dbClient().execute().createNamedGet("select-pokemon-named-arg") - .addParam("name", name) - .execute(); - } -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/SimpleDeleteService.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/SimpleDeleteService.java deleted file mode 100644 index 8e309069dd8..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/SimpleDeleteService.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.util.Map; - -import io.helidon.dbclient.DbClient; - -/** - * Service to test delete statements. - */ -public class SimpleDeleteService extends AbstractDeleteService { - - /** - * Create a new instance - * - * @param dbClient DbClient instance - * @param statements statements from configuration file - */ - public SimpleDeleteService(DbClient dbClient, Map statements) { - super(dbClient, statements); - } - - @Override - protected long testCreateNamedDeleteStrStrOrderArgs(int id) { - return dbClient().execute() - .createNamedDelete("delete-rayquaza", statement("delete-pokemon-order-arg")) - .addParam(id) - .execute(); - } - - @Override - protected long testCreateNamedDeleteStrNamedArgs(int id) { - return dbClient().execute() - .createNamedDelete("delete-pokemon-named-arg") - .addParam("id", id) - .execute(); - } - - @Override - protected long testCreateNamedDeleteStrOrderArgs(int id) { - return dbClient().execute() - .createNamedDelete("delete-pokemon-order-arg") - .addParam(id) - .execute(); - } - - @Override - protected long testCreateDeleteNamedArgs(int id) { - return dbClient().execute() - .createDelete(statement("delete-pokemon-named-arg")) - .addParam("id", id) - .execute(); - } - - @Override - protected long testCreateDeleteOrderArgs(int id) { - return dbClient().execute() - .createDelete(statement("delete-pokemon-order-arg")) - .addParam(id) - .execute(); - } - - @Override - protected long testNamedDeleteOrderArgs(int id) { - return dbClient().execute() - .namedDelete("delete-pokemon-order-arg", id); - } - - @Override - protected long testDeleteOrderArgs(int id) { - return dbClient().execute() - .delete(statement("delete-pokemon-order-arg"), id); - } - - @Override - protected long testCreateNamedDmlWithDeleteStrStrOrderArgs(int id) { - return dbClient().execute() - .createNamedDmlStatement("delete-mudkip", statement("delete-pokemon-order-arg")) - .addParam(id) - .execute(); - } - - @Override - protected long testCreateNamedDmlWithDeleteStrNamedArgs(int id) { - return dbClient().execute() - .createNamedDmlStatement("delete-pokemon-named-arg") - .addParam("id", id) - .execute(); - } - - @Override - protected long testCreateNamedDmlWithDeleteStrOrderArgs(int id) { - return dbClient().execute() - .createNamedDmlStatement("delete-pokemon-order-arg") - .addParam(id) - .execute(); - } - - @Override - protected long testCreateDmlWithDeleteNamedArgs(int id) { - return dbClient().execute() - .createDmlStatement(statement("delete-pokemon-named-arg")) - .addParam("id", id) - .execute(); - } - - @Override - protected long testCreateDmlWithDeleteOrderArgs(int id) { - return dbClient().execute() - .createDmlStatement(statement("delete-pokemon-order-arg")) - .addParam(id) - .execute(); - } - - @Override - protected long testNamedDmlWithDeleteOrderArgs(int id) { - return dbClient().execute() - .namedDml("delete-pokemon-order-arg", id); - } - - @Override - protected long testDmlWithDeleteOrderArgs(int id) { - return dbClient().execute() - .dml(statement("delete-pokemon-order-arg"), id); - } -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/SimpleGetService.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/SimpleGetService.java deleted file mode 100644 index e3199ab969c..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/SimpleGetService.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2020, 2023 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.tests.integration.dbclient.app.tests; - -import java.util.Map; -import java.util.Optional; - -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbRow; - -/** - * Service to test simple get statements. - */ -public class SimpleGetService extends AbstractGetService { - - /** - * Creates an instance of web resource to test set of basic DbClient gets. - * - * @param dbClient DbClient instance - * @param statements statements from configuration file - */ - public SimpleGetService(DbClient dbClient, Map statements) { - super(dbClient, statements); - } - - @Override - protected Optional testCreateNamedGetStrStrNamedArgs(String name) { - return dbClient().execute() - .createNamedGet("select-pikachu", statement("select-pokemon-named-arg")) - .addParam("name", name) - .execute(); - } - - @Override - protected Optional testCreateNamedGetStrNamedArgs(String name) { - return dbClient().execute() - .createNamedGet("select-pokemon-named-arg") - .addParam("name", name) - .execute(); - } - - @Override - protected Optional testCreateNamedGetStrOrderArgs(String name) { - return dbClient().execute() - .createNamedGet("select-pokemon-order-arg") - .addParam(name) - .execute(); - } - - @Override - protected Optional testCreateGetNamedArgs(String name) { - return dbClient().execute() - .createGet(statement("select-pokemon-named-arg")) - .addParam("name", name) - .execute(); - } - - @Override - protected Optional testCreateGetOrderArgs(String name) { - return dbClient().execute() - .createGet(statement("select-pokemon-order-arg")) - .addParam(name) - .execute(); - } - - @Override - protected Optional testNamedGetStrOrderArgs(String name) { - return dbClient().execute() - .namedGet("select-pokemon-order-arg", name); - } - - @Override - protected Optional testGetStrOrderArgs(String name) { - return dbClient().execute() - .get(statement("select-pokemon-order-arg"), name); - } -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/SimpleInsertService.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/SimpleInsertService.java deleted file mode 100644 index 806daa550cb..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/SimpleInsertService.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.util.Map; - -import io.helidon.dbclient.DbClient; - -/** - * Service to test simple insert statements. - */ -public class SimpleInsertService extends AbstractInsertService { - - /** - * Creates an instance of web resource to test set of basic DbClient inserts. - * - * @param dbClient DbClient instance - * @param statements statements from configuration file - */ - public SimpleInsertService(DbClient dbClient, Map statements) { - super(dbClient, statements); - } - - @Override - protected long testCreateNamedInsertStrStrNamedArgs(int id, String name) { - return dbClient().execute() - .createNamedInsert("insert-bulbasaur", statement("insert-pokemon-named-arg")) - .addParam("id", id) - .addParam("name", name) - .execute(); - } - - @Override - protected long testCreateNamedInsertStrNamedArgs(int id, String name) { - return dbClient().execute() - .createNamedInsert("insert-pokemon-named-arg") - .addParam("id", id) - .addParam("name", name) - .execute(); - } - - @Override - protected long testCreateNamedInsertStrOrderArgs(int id, String name) { - return dbClient().execute() - .createNamedInsert("insert-pokemon-order-arg") - .addParam(id) - .addParam(name) - .execute(); - } - - @Override - protected long testCreateInsertNamedArgs(int id, String name) { - return dbClient().execute() - .createInsert(statement("insert-pokemon-named-arg")) - .addParam("id", id) - .addParam("name", name) - .execute(); - } - - @Override - protected long testCreateInsertOrderArgs(int id, String name) { - return dbClient().execute() - .createInsert(statement("insert-pokemon-order-arg")) - .addParam(id) - .addParam(name) - .execute(); - } - - @Override - protected long testNamedInsertOrderArgs(int id, String name) { - return dbClient().execute() - .namedInsert("insert-pokemon-order-arg", id, name); - } - - @Override - protected long testInsertOrderArgs(int id, String name) { - return dbClient().execute() - .insert(statement("insert-pokemon-order-arg"), id, name); - } - - @Override - protected long testCreateNamedDmlWithInsertStrStrNamedArgs(int id, String name) { - return dbClient().execute() - .createNamedDmlStatement("insert-torchic", statement("insert-pokemon-named-arg")) - .addParam("id", id) - .addParam("name", name) - .execute(); - } - - @Override - protected long testCreateNamedDmlWithInsertStrNamedArgs(int id, String name) { - return dbClient().execute() - .createNamedDmlStatement("insert-pokemon-named-arg") - .addParam("id", id) - .addParam("name", name) - .execute(); - } - - @Override - protected long testCreateNamedDmlWithInsertStrOrderArgs(int id, String name) { - return dbClient().execute() - .createNamedDmlStatement("insert-pokemon-order-arg") - .addParam(id) - .addParam(name) - .execute(); - } - - @Override - protected long testCreateDmlWithInsertNamedArgs(int id, String name) { - return dbClient().execute() - .createDmlStatement(statement("insert-pokemon-named-arg")) - .addParam("id", id) - .addParam("name", name) - .execute(); - } - - @Override - protected long testCreateDmlWithInsertOrderArgs(int id, String name) { - return dbClient().execute() - .createDmlStatement(statement("insert-pokemon-order-arg")) - .addParam(id) - .addParam(name) - .execute(); - } - - @Override - protected long testNamedDmlWithInsertOrderArgs(int id, String name) { - return dbClient().execute() - .namedDml("insert-pokemon-order-arg", id, name); - } - - @Override - protected long testDmlWithInsertOrderArgs(int id, String name) { - return dbClient().execute() - .dml(statement("insert-pokemon-order-arg"), id, name); - } -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/SimpleQueryService.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/SimpleQueryService.java deleted file mode 100644 index 6ae42bd8b5d..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/SimpleQueryService.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.util.List; -import java.util.Map; - -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbRow; - -/** - * Service to test simple query statements. - */ -public class SimpleQueryService extends AbstractQueryService { - - /** - * Create a new instance. - * - * @param dbClient dbclient - * @param statements statements - */ - public SimpleQueryService(DbClient dbClient, Map statements) { - super(dbClient, statements); - } - - @Override - protected List testCreateNamedQueryStrStrOrderArgs(String name) { - return dbClient().execute() - .createNamedQuery("select-pikachu", statement("select-pokemon-order-arg")) - .addParam(name) - .execute() - .toList(); - } - - @Override - protected List testCreateNamedQueryStrNamedArgs(String name) { - return dbClient().execute() - .createNamedQuery("select-pokemon-named-arg") - .addParam("name", name) - .execute() - .toList(); - } - - @Override - protected List testCreateNamedQueryStrOrderArgs(String name) { - return dbClient().execute() - .createNamedQuery("select-pokemon-order-arg") - .addParam(name) - .execute() - .toList(); - } - - @Override - protected List testCreateQueryNamedArgs(String name) { - return dbClient().execute() - .createQuery(statement("select-pokemon-named-arg")) - .addParam("name", name) - .execute() - .toList(); - } - - @Override - protected List testCreateQueryOrderArgs(String name) { - return dbClient().execute() - .createQuery(statement("select-pokemon-order-arg")) - .addParam(name) - .execute() - .toList(); - } - - @Override - protected List testNamedQueryOrderArgs(String name) { - return dbClient().execute() - .namedQuery("select-pokemon-order-arg", name) - .toList(); - } - - @Override - protected List testQueryOrderArgs(String name) { - return dbClient().execute() - .query(statement("select-pokemon-order-arg"), name) - .toList(); - } -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/SimpleUpdateService.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/SimpleUpdateService.java deleted file mode 100644 index c0f0ebaee46..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/SimpleUpdateService.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.util.Map; - -import io.helidon.dbclient.DbClient; - -/** - * Service to test simple update statements. - */ -public class SimpleUpdateService extends AbstractUpdateService { - - /** - * Create a new instance. - * - * @param dbClient dbclient - * @param statements statements - */ - public SimpleUpdateService(DbClient dbClient, Map statements) { - super(dbClient, statements); - } - - @Override - protected long testCreateNamedUpdateStrStrNamedArgs(int id, String name) { - return dbClient().execute() - .createNamedUpdate("update-spearow", statement("update-pokemon-named-arg")) - .addParam("name", name) - .addParam("id", id) - .execute(); - } - - @Override - protected long testCreateNamedUpdateStrNamedArgs(int id, String name) { - return dbClient().execute() - .createNamedUpdate("update-pokemon-named-arg") - .addParam("name", name) - .addParam("id", id) - .execute(); - } - - @Override - protected long testCreateNamedUpdateStrOrderArgs(int id, String name) { - return dbClient().execute() - .createNamedUpdate("update-pokemon-order-arg") - .addParam(name) - .addParam(id) - .execute(); - } - - @Override - protected long testCreateUpdateNamedArgs(int id, String name) { - return dbClient().execute() - .createUpdate(statement("update-pokemon-named-arg")) - .addParam("name", name) - .addParam("id", id) - .execute(); - } - - @Override - protected long testCreateUpdateOrderArgs(int id, String name) { - return dbClient().execute() - .createUpdate(statement("update-pokemon-order-arg")) - .addParam(name) - .addParam(id) - .execute(); - } - - @Override - protected long testNamedUpdateNamedArgs(int id, String name) { - return dbClient().execute() - .namedUpdate("update-pokemon-order-arg", name, id); - } - - @Override - protected long testUpdateOrderArgs(int id, String name) { - return dbClient().execute() - .update(statement("update-pokemon-order-arg"), name, id); - } - - @Override - protected long testCreateNamedDmlWithUpdateStrStrNamedArgs(int id, String name) { - return dbClient().execute() - .createNamedDmlStatement("update-piplup", statement("update-pokemon-named-arg")) - .addParam("name", name) - .addParam("id", id) - .execute(); - } - - @Override - protected long testCreateNamedDmlWithUpdateStrNamedArgs(int id, String name) { - return dbClient().execute() - .createNamedDmlStatement("update-pokemon-named-arg") - .addParam("name", name) - .addParam("id", id) - .execute(); - } - - @Override - protected long testCreateNamedDmlWithUpdateStrOrderArgs(int id, String name) { - return dbClient().execute() - .createNamedDmlStatement("update-pokemon-order-arg") - .addParam(name) - .addParam(id) - .execute(); - } - - @Override - protected long testCreateDmlWithUpdateNamedArgs(int id, String name) { - return dbClient().execute() - .createDmlStatement(statement("update-pokemon-named-arg")) - .addParam("name", name) - .addParam("id", id) - .execute(); - } - - @Override - protected long testCreateDmlWithUpdateOrderArgs(int id, String name) { - return dbClient().execute() - .createDmlStatement(statement("update-pokemon-order-arg")) - .addParam(name) - .addParam(id) - .execute(); - } - - @Override - protected long testNamedDmlWithUpdateOrderArgs(int id, String name) { - return dbClient().execute() - .namedDml("update-pokemon-order-arg", name, id); - } - - @Override - protected long testDmlWithUpdateOrderArgs(int id, String name) { - return dbClient().execute() - .dml(statement("update-pokemon-order-arg"), name, id); - } -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/StatementDmlService.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/StatementDmlService.java deleted file mode 100644 index 137bce519d5..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/StatementDmlService.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.lang.System.Logger.Level; -import java.util.List; -import java.util.Map; - -import io.helidon.http.NotFoundException; -import io.helidon.dbclient.DbClient; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; - -import jakarta.json.Json; - -import static io.helidon.tests.integration.harness.AppResponse.okStatus; - -/** - * Service to test DbStatementDml methods. - */ -public class StatementDmlService extends AbstractService { - - private static final System.Logger LOGGER = System.getLogger(StatementDmlService.class.getName()); - - public StatementDmlService(DbClient dbClient, Map statements) { - super(dbClient, statements); - } - - @Override - public void routing(HttpRules rules) { - rules.get("/{testName}", this::executeTest); - } - - private void executeTest(ServerRequest request, ServerResponse response) { - String testName = pathParam(request, "testName"); - String name = queryParam(request, QueryParams.NAME); - int id = Integer.parseInt(queryParam(request, QueryParams.ID)); - LOGGER.log(Level.DEBUG, () -> String.format("Running %s.%s on server", getClass().getSimpleName(), testName)); - long count = switch (testName) { - case "testDmlArrayParams" -> testDmlArrayParams(id, name); - case "testDmlListParams" -> testDmlListParams(id, name); - case "testDmlMapParams" -> testDmlMapParams(id, name); - case "testDmlOrderParam" -> testDmlOrderParam(id, name); - case "testDmlNamedParam" -> testDmlNamedParam(id, name); - case "testDmlMappedNamedParam" -> testDmlMappedNamedParam(id, name); - case "testDmlMappedOrderParam" -> testDmlMappedOrderParam(id, name); - default -> throw new NotFoundException("test not found: " + testName); - }; - response.send(okStatus(Json.createValue(count))); - } - - /** - * Verify {@code params(Object... parameters)} parameters setting method. - * - * @param id parameter - * @param name parameter - * @return count - */ - private long testDmlArrayParams(int id, String name) { - return dbClient().execute() - .createNamedDmlStatement("update-pokemon-order-arg") - .params(name, id) - .execute(); - } - - /** - * Verify {@code params(List)} parameters setting method. - * - * @param id parameter - * @param name parameter - * @return count - */ - private long testDmlListParams(int id, String name) { - return dbClient().execute() - .createNamedDmlStatement("update-pokemon-order-arg") - .params(List.of(name, id)) - .execute(); - } - - /** - * Verify {@code params(Map)} parameters setting method. - * - * @param id parameter - * @param name parameter - * @return count - */ - private long testDmlMapParams(int id, String name) { - return dbClient().execute() - .createNamedDmlStatement("update-pokemon-named-arg") - .params(Map.of("name", name, "id", id)) - .execute(); - } - - /** - * Verify {@code addParam(Object parameter)} parameters setting method. - * - * @param id parameter - * @param name parameter - * @return count - */ - private long testDmlOrderParam(int id, String name) { - return dbClient().execute() - .createNamedDmlStatement("update-pokemon-order-arg") - .addParam(name) - .addParam(id) - .execute(); - } - - /** - * Verify {@code addParam(String name, Object parameter)} parameters setting method. - * - * @param id parameter - * @param name parameter - * @return count - */ - private long testDmlNamedParam(int id, String name) { - return dbClient().execute() - .createNamedDmlStatement("update-pokemon-named-arg") - .addParam("name", name) - .addParam("id", id) - .execute(); - } - - /** - * Verify {@code namedParam(Object parameters)} mapped parameters setting method. - * - * @param id parameter - * @param name parameter - * @return count - */ - private long testDmlMappedNamedParam(int id, String name) { - Pokemon pokemon = new Pokemon(id, name, Pokemon.POKEMONS.get(id).getTypesArray()); - return dbClient().execute() - .createNamedDmlStatement("update-pokemon-named-arg") - .namedParam(pokemon) - .execute(); - } - - /** - * Verify {@code indexedParam(Object parameters)} mapped parameters setting method. - * - * @param id parameter - * @param name parameter - * @return count - */ - private long testDmlMappedOrderParam(int id, String name) { - Pokemon pokemon = new Pokemon(id, name, Pokemon.POKEMONS.get(id).getTypesArray()); - return dbClient().execute() - .createNamedDmlStatement("update-pokemon-order-arg") - .indexedParam(pokemon) - .execute(); - } -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/StatementGetService.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/StatementGetService.java deleted file mode 100644 index de08450d2de..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/StatementGetService.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.lang.System.Logger.Level; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import io.helidon.http.NotFoundException; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbRow; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; -import io.helidon.tests.integration.dbclient.common.model.RangePoJo; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; - -import jakarta.json.JsonObject; - -import static io.helidon.tests.integration.harness.AppResponse.okStatus; - -/** - * Service to test get statements. - */ -public class StatementGetService extends AbstractService { - - private static final System.Logger LOGGER = System.getLogger(StatementGetService.class.getName()); - - /** - * Create a new instance - * - * @param dbClient dbclient - * @param statements statements - */ - public StatementGetService(DbClient dbClient, Map statements) { - super(dbClient, statements); - } - - @Override - public void routing(HttpRules rules) { - rules.get("/{testName}", this::executeTest); - } - - private void executeTest(ServerRequest request, ServerResponse response) { - String testName = pathParam(request, "testName"); - int fromId = Integer.parseInt(queryParam(request, QueryParams.FROM_ID)); - int toId = Integer.parseInt(queryParam(request, QueryParams.TO_ID)); - LOGGER.log(Level.DEBUG, () -> String.format("Running %s.%s on server", getClass().getSimpleName(), testName)); - Optional result = switch (testName) { - case "testGetArrayParams" -> testGetArrayParams(fromId, toId); - case "testGetListParams" -> testGetListParams(fromId, toId); - case "testGetMapParams" -> testGetMapParams(fromId, toId); - case "testGetOrderParam" -> testGetOrderParam(fromId, toId); - case "testGetNamedParam" -> testGetNamedParam(fromId, toId); - case "testGetMappedNamedParam" -> testGetMappedNamedParam(fromId, toId); - case "testGetMappedOrderParam" -> testGetMappedOrderParam(fromId, toId); - default -> throw new NotFoundException("test not found: " + testName); - }; - JsonObject jsonObject = result - .map(row -> row.as(JsonObject.class)) - .orElse(JsonObject.EMPTY_JSON_OBJECT); - response.send(okStatus(jsonObject)); - } - - /** - * Verify {@code params(Object... parameters)} parameters setting method. - * - * @param fromId parameter - * @param toId parameter - * @return row - */ - private Optional testGetArrayParams(int fromId, int toId) { - return dbClient().execute() - .createNamedGet("select-pokemons-idrng-order-arg") - .params(fromId, toId) - .execute(); - } - - /** - * Verify {@code params(List)} parameters setting method. - * - * @param fromId parameter - * @param toId parameter - * @return row - */ - private Optional testGetListParams(int fromId, int toId) { - return dbClient().execute() - .createNamedGet("select-pokemons-idrng-order-arg") - .params(List.of(fromId, toId)) - .execute(); - } - - /** - * Verify {@code params(Map)} parameters setting method. - * - * @param fromId parameter - * @param toId parameter - * @return row - */ - private Optional testGetMapParams(int fromId, int toId) { - return dbClient().execute() - .createNamedGet("select-pokemons-idrng-named-arg") - .params(Map.of("idmin", fromId, "idmax", toId)) - .execute(); - } - - /** - * Verify {@code addParam(Object parameter)} parameters setting method. - * - * @param fromId parameter - * @param toId parameter - * @return row - */ - private Optional testGetOrderParam(int fromId, int toId) { - return dbClient().execute() - .createNamedGet("select-pokemons-idrng-order-arg") - .addParam(fromId) - .addParam(toId) - .execute(); - } - - /** - * Verify {@code addParam(String name, Object parameter)} parameters setting method. - * - * @param fromId parameter - * @param toId parameter - * @return row - */ - private Optional testGetNamedParam(int fromId, int toId) { - return dbClient().execute() - .createNamedGet("select-pokemons-idrng-named-arg") - .addParam("idmin", fromId) - .addParam("idmax", toId) - .execute(); - } - - /** - * Verify {@code namedParam(Object parameters)} mapped parameters setting method. - * - * @param fromId parameter - * @param toId parameter - * @return row - */ - private Optional testGetMappedNamedParam(int fromId, int toId) { - RangePoJo range = new RangePoJo(fromId, toId); - return dbClient().execute() - .createNamedGet("select-pokemons-idrng-named-arg") - .namedParam(range) - .execute(); - } - - /** - * Verify {@code indexedParam(Object parameters)} mapped parameters setting method. - * - * @param fromId parameter - * @param toId parameter - * @return row - */ - private Optional testGetMappedOrderParam(int fromId, int toId) { - RangePoJo range = new RangePoJo(fromId, toId); - return dbClient().execute() - .createNamedGet("select-pokemons-idrng-order-arg") - .indexedParam(range) - .execute(); - } -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/StatementQueryService.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/StatementQueryService.java deleted file mode 100644 index a1eabc1563a..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/StatementQueryService.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.lang.System.Logger.Level; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; - -import io.helidon.http.NotFoundException; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbRow; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; -import io.helidon.tests.integration.dbclient.common.model.RangePoJo; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; - -import jakarta.json.Json; -import jakarta.json.JsonArray; -import jakarta.json.JsonArrayBuilder; -import jakarta.json.JsonObject; - -import static io.helidon.tests.integration.harness.AppResponse.okStatus; - -/** - * Service to test query statements. - */ -public class StatementQueryService extends AbstractService { - - private static final System.Logger LOGGER = System.getLogger(StatementGetService.class.getName()); - - /** - * Create a new instance. - * - * @param dbClient dbclient - * @param statements statements - */ - public StatementQueryService(DbClient dbClient, Map statements) { - super(dbClient, statements); - } - - @Override - public void routing(HttpRules rules) { - rules.get("/{testName}", this::executeTest); - } - - private void executeTest(ServerRequest request, ServerResponse response) { - String testName = pathParam(request, "testName"); - int fromId = Integer.parseInt(queryParam(request, QueryParams.FROM_ID)); - int toId = Integer.parseInt(queryParam(request, QueryParams.TO_ID)); - LOGGER.log(Level.DEBUG, () -> String.format("Running %s.%s on server", getClass().getSimpleName(), testName)); - Stream result = switch (testName) { - case "testQueryArrayParams" -> testQueryArrayParams(fromId, toId); - case "testQueryListParams" -> testQueryListParams(fromId, toId); - case "testQueryMapParams" -> testQueryMapParams(fromId, toId); - case "testQueryOrderParam" -> testQueryOrderParam(fromId, toId); - case "testQueryNamedParam" -> testQueryNamedParam(fromId, toId); - case "testQueryMappedNamedParam" -> testQueryMappedNamedParam(fromId, toId); - case "testQueryMappedOrderParam" -> testQueryMappedOrderParam(fromId, toId); - default -> throw new NotFoundException("test not found: " + testName); - }; - JsonArray jsonArray = result - .map(row -> row.as(JsonObject.class)) - .collect(Json::createArrayBuilder, JsonArrayBuilder::add, JsonArrayBuilder::add) - .build(); - response.send(okStatus(jsonArray)); - } - - /** - * Verify {@code params(Object... parameters)} parameters setting method. - * - * @param fromId parameter - * @param toId parameter - * @return rows - */ - private Stream testQueryArrayParams(int fromId, int toId) { - return dbClient().execute() - .createNamedQuery("select-pokemons-idrng-order-arg") - .params(fromId, toId) - .execute(); - } - - /** - * Verify {@code params(List)} parameters setting method. - * - * @param fromId parameter - * @param toId parameter - * @return rows - */ - private Stream testQueryListParams(int fromId, int toId) { - return dbClient().execute() - .createNamedQuery("select-pokemons-idrng-order-arg") - .params(List.of(fromId, toId)) - .execute(); - } - - /** - * Verify {@code params(Map)} parameters setting method. - * - * @param fromId parameter - * @param toId parameter - * @return rows - */ - private Stream testQueryMapParams(int fromId, int toId) { - return dbClient().execute() - .createNamedQuery("select-pokemons-idrng-named-arg") - .params(Map.of("idmin", fromId, "idmax", toId)) - .execute(); - } - - /** - * Verify {@code addParam(Object parameter)} parameters setting method. - * - * @param fromId parameter - * @param toId parameter - * @return rows - */ - private Stream testQueryOrderParam(int fromId, int toId) { - return dbClient().execute() - .createNamedQuery("select-pokemons-idrng-order-arg") - .addParam(fromId) - .addParam(toId) - .execute(); - } - - /** - * Verify {@code addParam(String name, Object parameter)} parameters setting method. - * - * @param fromId parameter - * @param toId parameter - * @return rows - */ - private Stream testQueryNamedParam(int fromId, int toId) { - return dbClient().execute() - .createNamedQuery("select-pokemons-idrng-named-arg") - .addParam("idmin", fromId) - .addParam("idmax", toId) - .execute(); - } - - /** - * Verify {@code namedParam(Object parameters)} mapped parameters setting method. - * - * @param fromId parameter - * @param toId parameter - * @return rows - */ - private Stream testQueryMappedNamedParam(int fromId, int toId) { - RangePoJo range = new RangePoJo(fromId, toId); - return dbClient().execute().createNamedQuery("select-pokemons-idrng-named-arg") - .namedParam(range) - .execute(); - } - - /** - * Verify {@code indexedParam(Object parameters)} mapped parameters setting method. - * - * @param fromId parameter - * @param toId parameter - * @return rows - */ - private Stream testQueryMappedOrderParam(int fromId, int toId) { - RangePoJo range = new RangePoJo(fromId, toId); - return dbClient().execute().createNamedQuery("select-pokemons-idrng-order-arg") - .indexedParam(range) - .execute(); - } -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/TransactionDeleteService.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/TransactionDeleteService.java deleted file mode 100644 index 0dfb7953424..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/TransactionDeleteService.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.util.Map; - -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbTransaction; - -/** - * Service to test delete statements in transaction. - */ -public class TransactionDeleteService extends AbstractDeleteService { - - public TransactionDeleteService(DbClient dbClient, Map statements) { - super(dbClient, statements); - } - - @Override - protected long testCreateNamedDeleteStrStrOrderArgs(int id) { - DbTransaction tx = dbClient().transaction(); - long count = tx.createNamedDelete("delete-rayquaza", statement("delete-pokemon-order-arg")) - .addParam(id) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testCreateNamedDeleteStrNamedArgs(int id) { - DbTransaction tx = dbClient().transaction(); - long count = tx.createNamedDelete("delete-pokemon-named-arg") - .addParam("id", id) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testCreateNamedDeleteStrOrderArgs(int id) { - DbTransaction tx = dbClient().transaction(); - long count = tx.createNamedDelete("delete-pokemon-order-arg") - .addParam(id) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testCreateDeleteNamedArgs(int id) { - DbTransaction tx = dbClient().transaction(); - long count = tx.createDelete(statement("delete-pokemon-named-arg")) - .addParam("id", id) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testCreateDeleteOrderArgs(int id) { - DbTransaction tx = dbClient().transaction(); - long count = tx.createDelete(statement("delete-pokemon-order-arg")) - .addParam(id) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testNamedDeleteOrderArgs(int id) { - DbTransaction tx = dbClient().transaction(); - long count = tx.namedDelete("delete-pokemon-order-arg", id); - tx.commit(); - return count; - } - - @Override - protected long testDeleteOrderArgs(int id) { - DbTransaction tx = dbClient().transaction(); - long count = tx.delete(statement("delete-pokemon-order-arg"), id); - tx.commit(); - return count; - } - - @Override - protected long testCreateNamedDmlWithDeleteStrStrOrderArgs(int id) { - DbTransaction tx = dbClient().transaction(); - long count = tx.createNamedDmlStatement("delete-mudkip", statement("delete-pokemon-order-arg")) - .addParam(id) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testCreateNamedDmlWithDeleteStrNamedArgs(int id) { - DbTransaction tx = dbClient().transaction(); - long count = tx.createNamedDmlStatement("delete-pokemon-named-arg") - .addParam("id", id) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testCreateNamedDmlWithDeleteStrOrderArgs(int id) { - DbTransaction tx = dbClient().transaction(); - long count = tx.createNamedDmlStatement("delete-pokemon-order-arg") - .addParam(id) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testCreateDmlWithDeleteNamedArgs(int id) { - DbTransaction tx = dbClient().transaction(); - long count = tx.createDmlStatement(statement("delete-pokemon-named-arg")) - .addParam("id", id) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testCreateDmlWithDeleteOrderArgs(int id) { - DbTransaction tx = dbClient().transaction(); - long count = tx - .createDmlStatement(statement("delete-pokemon-order-arg")) - .addParam(id) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testNamedDmlWithDeleteOrderArgs(int id) { - DbTransaction tx = dbClient().transaction(); - long count = tx.namedDml("delete-pokemon-order-arg", id); - tx.commit(); - return count; - } - - @Override - protected long testDmlWithDeleteOrderArgs(int id) { - DbTransaction tx = dbClient().transaction(); - long count = tx.dml(statement("delete-pokemon-order-arg"), id); - tx.commit(); - return count; - } -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/TransactionGetService.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/TransactionGetService.java deleted file mode 100644 index 917a21dbdb5..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/TransactionGetService.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.util.Map; -import java.util.Optional; - -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbRow; -import io.helidon.dbclient.DbTransaction; - -/** - * Service to test set of get statements calls in transaction. - */ -public class TransactionGetService extends AbstractGetService { - - public TransactionGetService(DbClient dbClient, Map statements) { - super(dbClient, statements); - } - - @Override - protected Optional testCreateNamedGetStrStrNamedArgs(String name) { - DbTransaction tx = dbClient().transaction(); - Optional result = tx - .createNamedGet("select-pikachu", statement("select-pokemon-named-arg")) - .addParam("name", name) - .execute(); - tx.commit(); - return result; - } - - @Override - protected Optional testCreateNamedGetStrNamedArgs(String name) { - DbTransaction tx = dbClient().transaction(); - Optional result = tx - .createNamedGet("select-pokemon-named-arg") - .addParam("name", name) - .execute(); - tx.commit(); - return result; - } - - @Override - protected Optional testCreateNamedGetStrOrderArgs(String name) { - DbTransaction tx = dbClient().transaction(); - Optional result = tx - .createNamedGet("select-pokemon-order-arg") - .addParam(name) - .execute(); - tx.commit(); - return result; - } - - @Override - protected Optional testCreateGetNamedArgs(String name) { - DbTransaction tx = dbClient().transaction(); - Optional result = tx - .createGet(statement("select-pokemon-named-arg")) - .addParam("name", name) - .execute(); - tx.commit(); - return result; - } - - @Override - protected Optional testCreateGetOrderArgs(String name) { - DbTransaction tx = dbClient().transaction(); - Optional result = tx - .createGet(statement("select-pokemon-order-arg")) - .addParam(name) - .execute(); - tx.commit(); - return result; - } - - @Override - protected Optional testNamedGetStrOrderArgs(String name) { - DbTransaction tx = dbClient().transaction(); - Optional result = tx.namedGet("select-pokemon-order-arg", name); - tx.commit(); - return result; - } - - @Override - protected Optional testGetStrOrderArgs(String name) { - DbTransaction tx = dbClient().transaction(); - Optional result = tx.get(statement("select-pokemon-order-arg"), name); - tx.commit(); - return result; - } -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/TransactionInsertService.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/TransactionInsertService.java deleted file mode 100644 index aabcdb27c84..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/TransactionInsertService.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.util.Map; - -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbTransaction; - -/** - * Service to test simple insert statements in transaction. - */ -public class TransactionInsertService extends AbstractInsertService { - - /** - * Create a new instance. - * - * @param dbClient dbclient - * @param statements statements - */ - public TransactionInsertService(DbClient dbClient, Map statements) { - super(dbClient, statements); - } - - @Override - protected long testCreateNamedInsertStrStrNamedArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx - .createNamedInsert("insert-bulbasaur", statement("insert-pokemon-named-arg")) - .addParam("id", id) - .addParam("name", name) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testCreateNamedInsertStrNamedArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx.createNamedInsert("insert-pokemon-named-arg") - .addParam("id", id) - .addParam("name", name) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testCreateNamedInsertStrOrderArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx.createNamedInsert("insert-pokemon-order-arg") - .addParam(id) - .addParam(name) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testCreateInsertNamedArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx.createInsert(statement("insert-pokemon-named-arg")) - .addParam("id", id) - .addParam("name", name) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testCreateInsertOrderArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx.createInsert(statement("insert-pokemon-order-arg")) - .addParam(id) - .addParam(name) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testNamedInsertOrderArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx.namedInsert("insert-pokemon-order-arg", id, name); - tx.commit(); - return count; - } - - @Override - protected long testInsertOrderArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx.insert(statement("insert-pokemon-order-arg"), id, name); - tx.commit(); - return count; - } - - @Override - protected long testCreateNamedDmlWithInsertStrStrNamedArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx.createNamedDmlStatement("insert-torchic", statement("insert-pokemon-named-arg")) - .addParam("id", id) - .addParam("name", name) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testCreateNamedDmlWithInsertStrNamedArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx.createNamedDmlStatement("insert-pokemon-named-arg") - .addParam("id", id) - .addParam("name", name) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testCreateNamedDmlWithInsertStrOrderArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx.createNamedDmlStatement("insert-pokemon-order-arg") - .addParam(id) - .addParam(name) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testCreateDmlWithInsertNamedArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx.createDmlStatement(statement("insert-pokemon-named-arg")) - .addParam("id", id) - .addParam("name", name) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testCreateDmlWithInsertOrderArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx.createDmlStatement(statement("insert-pokemon-order-arg")) - .addParam(id) - .addParam(name) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testNamedDmlWithInsertOrderArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx.namedDml("insert-pokemon-order-arg", id, name); - tx.commit(); - return count; - } - - @Override - protected long testDmlWithInsertOrderArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx.dml(statement("insert-pokemon-order-arg"), id, name); - tx.commit(); - return count; - } -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/TransactionQueryService.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/TransactionQueryService.java deleted file mode 100644 index 2d3d04bc33b..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/TransactionQueryService.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.util.List; -import java.util.Map; - -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbRow; -import io.helidon.dbclient.DbTransaction; - -/** - * Service to test simple query statements in transaction. - */ -public class TransactionQueryService extends AbstractQueryService { - - /** - * Create a new instance. - * - * @param dbClient dbclient - * @param statements statements - */ - public TransactionQueryService(DbClient dbClient, Map statements) { - super(dbClient, statements); - } - - @Override - protected List testCreateNamedQueryStrStrOrderArgs(String name) { - DbTransaction tx = dbClient().transaction(); - List rows = tx.createNamedQuery("select-pikachu", statement("select-pokemon-order-arg")) - .addParam(name) - .execute() - .toList(); - tx.commit(); - return rows; - } - - @Override - protected List testCreateNamedQueryStrNamedArgs(String name) { - DbTransaction tx = dbClient().transaction(); - List rows = tx - .createNamedQuery("select-pokemon-named-arg") - .addParam("name", name) - .execute() - .toList(); - tx.commit(); - return rows; - } - - @Override - protected List testCreateNamedQueryStrOrderArgs(String name) { - DbTransaction tx = dbClient().transaction(); - List rows = tx - .createNamedQuery("select-pokemon-order-arg") - .addParam(name) - .execute() - .toList(); - tx.commit(); - return rows; - } - - @Override - protected List testCreateQueryNamedArgs(String name) { - DbTransaction tx = dbClient().transaction(); - List rows = tx - .createQuery(statement("select-pokemon-named-arg")) - .addParam("name", name) - .execute() - .toList(); - tx.commit(); - return rows; - } - - @Override - protected List testCreateQueryOrderArgs(String name) { - DbTransaction tx = dbClient().transaction(); - List rows = tx - .createQuery(statement("select-pokemon-order-arg")) - .addParam(name) - .execute() - .toList(); - tx.commit(); - return rows; - } - - @Override - protected List testNamedQueryOrderArgs(String name) { - DbTransaction tx = dbClient().transaction(); - List rows = tx - .namedQuery("select-pokemon-order-arg", name) - .toList(); - tx.commit(); - return rows; - } - - @Override - protected List testQueryOrderArgs(String name) { - DbTransaction tx = dbClient().transaction(); - List rows = tx - .query(statement("select-pokemon-order-arg"), name) - .toList(); - tx.commit(); - return rows; - } -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/TransactionUpdateService.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/TransactionUpdateService.java deleted file mode 100644 index 2d9fc38ed2d..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tests/TransactionUpdateService.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.util.Map; - -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbTransaction; - -/** - * Service to test simple update statements in transaction. - */ -public class TransactionUpdateService extends AbstractUpdateService { - - /** - * Create a new instance. - * - * @param dbClient dbclient - * @param statements statements - */ - public TransactionUpdateService(DbClient dbClient, Map statements) { - super(dbClient, statements); - } - - @Override - protected long testCreateNamedUpdateStrStrNamedArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx.createNamedUpdate("update-spearow", statement("update-pokemon-named-arg")) - .addParam("name", name) - .addParam("id", id) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testCreateNamedUpdateStrNamedArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx - .createNamedUpdate("update-pokemon-named-arg") - .addParam("name", name) - .addParam("id", id) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testCreateNamedUpdateStrOrderArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx.createNamedUpdate("update-pokemon-order-arg") - .addParam(name) - .addParam(id) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testCreateUpdateNamedArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx.createUpdate(statement("update-pokemon-named-arg")) - .addParam("name", name) - .addParam("id", id) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testCreateUpdateOrderArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx.createUpdate(statement("update-pokemon-order-arg")) - .addParam(name) - .addParam(id) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testNamedUpdateNamedArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx.namedUpdate("update-pokemon-order-arg", name, id); - tx.commit(); - return count; - } - - @Override - protected long testUpdateOrderArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx.update(statement("update-pokemon-order-arg"), name, id); - tx.commit(); - return count; - } - - @Override - protected long testCreateNamedDmlWithUpdateStrStrNamedArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx.createNamedDmlStatement("update-piplup", statement("update-pokemon-named-arg")) - .addParam("name", name) - .addParam("id", id) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testCreateNamedDmlWithUpdateStrNamedArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx.createNamedDmlStatement("update-pokemon-named-arg") - .addParam("name", name) - .addParam("id", id) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testCreateNamedDmlWithUpdateStrOrderArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx.createNamedDmlStatement("update-pokemon-order-arg") - .addParam(name) - .addParam(id) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testCreateDmlWithUpdateNamedArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx.createDmlStatement(statement("update-pokemon-named-arg")) - .addParam("name", name) - .addParam("id", id) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testCreateDmlWithUpdateOrderArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx.createDmlStatement(statement("update-pokemon-order-arg")) - .addParam(name) - .addParam(id) - .execute(); - tx.commit(); - return count; - } - - @Override - protected long testNamedDmlWithUpdateOrderArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx.namedDml("update-pokemon-order-arg", name, id); - tx.commit(); - return count; - } - - @Override - protected long testDmlWithUpdateOrderArgs(int id, String name) { - DbTransaction tx = dbClient().transaction(); - long count = tx.dml(statement("update-pokemon-order-arg"), name, id); - tx.commit(); - return count; - } -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tools/ExitService.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tools/ExitService.java deleted file mode 100644 index 01171894c25..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tools/ExitService.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tools; - -import io.helidon.common.media.type.MediaTypes; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.http.HttpRules; -import io.helidon.webserver.http.HttpService; -import io.helidon.webserver.http.ServerRequest; -import io.helidon.webserver.http.ServerResponse; - -/** - * Service to terminate web server. - */ -public class ExitService implements HttpService { - - private WebServer server; - - @Override - public void routing(HttpRules rules) { - rules.get("/", this::exit); - } - - /** - * Set the server instance. - * - * @param server server - */ - public void setServer(WebServer server) { - this.server = server; - } - - private void exit(ServerRequest request, ServerResponse response) { - response.headers().contentType(MediaTypes.TEXT_PLAIN); - response.send("Testing web application shutting down."); - server.stop(); - } -} diff --git a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tools/QueryParams.java b/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tools/QueryParams.java deleted file mode 100644 index 368b54adf82..00000000000 --- a/tests/integration/dbclient/app/src/main/java/io/helidon/tests/integration/dbclient/app/tools/QueryParams.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tools; - -import java.util.HashMap; - -/** - * Query parameters map with builder. - */ -public class QueryParams extends HashMap { - - /** - * Query parameter {@code name}. - */ - public static final String NAME = "name"; - /** - * Query parameter {@code id} - */ - public static final String ID = "id"; - /** - * Query parameter {@code fromid}. - */ - public static final String FROM_ID = "fromid"; - /** - * Query parameter {@code toid}. - */ - public static final String TO_ID = "toid"; - - /** - * Shortcut for single parameter in a query. - * - * @param name name of parameter - * @param value value of parameter - * @return query parameters {@code Map} with provided single value - */ - public static QueryParams single(String name, String value) { - return QueryParams.builder().add(name, value).build(); - } - - /** - * Create query parameters builder. - * - * @return new query parameters builder instance - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Query parameter builder. - */ - public static final class Builder { - - private final QueryParams params; - - private Builder() { - params = new QueryParams(); - } - - /** - * Add query parameter. - * - * @param name name of parameter - * @param value value of parameter - * @return updated query parameter builder - */ - public Builder add(String name, String value) { - params.put(name, value); - return this; - } - - /** - * Build query parameters with parameters currently stored in builder. - * - * @return query parameters {@code Map}. - */ - public QueryParams build() { - return params; - } - } -} diff --git a/tests/integration/dbclient/app/src/main/resources/h2.yaml b/tests/integration/dbclient/app/src/main/resources/h2.yaml deleted file mode 100644 index 9961aa9db56..00000000000 --- a/tests/integration/dbclient/app/src/main/resources/h2.yaml +++ /dev/null @@ -1,61 +0,0 @@ -# -# Copyright (c) 2022, 2023 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. -# - -db: - source: jdbc - connection: - url: ${db.url} - username: ${db.user} - password: ${db.password} - health-check: - type: query - statement: "SELECT 0" - statements: - ping-query: "SELECT 0" - create-types: "CREATE TABLE Types (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(64) NOT NULL)" - create-pokemons: "CREATE TABLE Pokemons (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(64) NOT NULL)" - create-poketypes: "CREATE TABLE PokemonTypes (id_pokemon INTEGER NOT NULL, id_type INTEGER NOT NULL REFERENCES Types(id))" - drop-types: "DROP TABLE Types" - drop-pokemons: "DROP TABLE Pokemons" - drop-poketypes: "DROP TABLE PokemonTypes" - insert-type: "INSERT INTO Types(id, name) VALUES(?, ?)" - insert-pokemon: "INSERT INTO Pokemons(id, name) VALUES(?, ?)" - insert-poketype: "INSERT INTO PokemonTypes(id_pokemon, id_type) VALUES(?, ?)" - select-types: "SELECT id, name FROM Types" - select-pokemons: "SELECT id, name FROM Pokemons" - select-poketypes: "SELECT id_pokemon, id_type FROM PokemonTypes p WHERE id_pokemon = ?" - get-pokemon-by-id: "SELECT id, name FROM Pokemons WHERE id = ?" - get-pokemon-types: "SELECT t.id AS id, t.name AS name FROM Types t INNER JOIN PokemonTypes pt ON pt.id_type = t.id WHERE pt.id_pokemon = ?" - select-poketypes-all: "SELECT id_pokemon, id_type FROM PokemonTypes" - select-max-id: "SELECT MAX(id) FROM Pokemons" - select-pokemon-named-arg: "SELECT id, name FROM Pokemons WHERE name=:name" - select-pokemon-order-arg: "SELECT id, name FROM Pokemons WHERE name=?" - insert-pokemon-named-arg: "INSERT INTO Pokemons(id, name) VALUES(:id, :name)" - insert-pokemon-order-arg: "INSERT INTO Pokemons(id, name) VALUES(?, ?)" - insert-pokemon-order-arg-rev: "INSERT INTO Pokemons(name, id) VALUES(?, ?)" - select-pokemon-by-id: "SELECT id, name FROM Pokemons WHERE id=?" - update-pokemon-named-arg: "UPDATE Pokemons SET name=:name WHERE id=:id" - update-pokemon-order-arg: "UPDATE Pokemons SET name=? WHERE id=?" - delete-pokemon-named-arg: "DELETE FROM Pokemons WHERE id=:id" - delete-pokemon-order-arg: "DELETE FROM Pokemons WHERE id=?" - delete-pokemon-full-named-arg: "DELETE FROM Pokemons WHERE name=:name AND id=:id" - delete-pokemon-full-order-arg: "DELETE FROM Pokemons WHERE name=? AND id=?" - select-pokemons-idrng-named-arg: "SELECT id, name FROM Pokemons WHERE id > :idmin AND id < :idmax" - select-pokemons-idrng-order-arg: "SELECT id, name FROM Pokemons WHERE id > ? AND id < ?" - select-pokemons-error-arg: "SELECT id, name FROM Pokemons WHERE id > :id AND name = ?" - -test: - ping-dml: false diff --git a/tests/integration/dbclient/app/src/main/resources/logging.properties b/tests/integration/dbclient/app/src/main/resources/logging.properties deleted file mode 100644 index e1b27ef2055..00000000000 --- a/tests/integration/dbclient/app/src/main/resources/logging.properties +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2020, 2023 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. -# - -handlers=io.helidon.logging.jul.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=WARNING -io.helidon.level=INFO -io.helidon.config.level=INFO -io.helidon.webserver.http.level=WARNING -io.helidon.tests.integration.dbclient.app.level=INFO diff --git a/tests/integration/dbclient/app/src/main/resources/mysql.yaml b/tests/integration/dbclient/app/src/main/resources/mysql.yaml deleted file mode 100644 index a1ab39bfd79..00000000000 --- a/tests/integration/dbclient/app/src/main/resources/mysql.yaml +++ /dev/null @@ -1,59 +0,0 @@ -# -# Copyright (c) 2019, 2023 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. -# - -db: - source: jdbc - connection: - url: ${db.url} - username: ${db.user} - password: ${db.password} - health-check: - type: dml - statement: "DO 0" - statements: - ping-dml: "DO 0" - ping-query: "SELECT 0" - create-types: "CREATE TABLE Types (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(64) NOT NULL)" - create-pokemons: "CREATE TABLE Pokemons (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(64) NOT NULL)" - create-poketypes: "CREATE TABLE PokemonTypes (id_pokemon INTEGER NOT NULL, id_type INTEGER NOT NULL REFERENCES Types(id))" - drop-types: "DROP TABLE Types" - drop-pokemons: "DROP TABLE Pokemons" - drop-poketypes: "DROP TABLE PokemonTypes" - insert-type: "INSERT INTO Types(id, name) VALUES(?, ?)" - insert-pokemon: "INSERT INTO Pokemons(id, name) VALUES(?, ?)" - insert-poketype: "INSERT INTO PokemonTypes(id_pokemon, id_type) VALUES(?, ?)" - select-types: "SELECT id, name FROM Types" - select-pokemons: "SELECT id, name FROM Pokemons" - select-poketypes: "SELECT id_pokemon, id_type FROM PokemonTypes p WHERE id_pokemon = ?" - get-pokemon-by-id: "SELECT id, name FROM Pokemons WHERE id = ?" - get-pokemon-types: "SELECT t.id AS id, t.name AS name FROM Types t INNER JOIN PokemonTypes pt ON pt.id_type = t.id WHERE pt.id_pokemon = ?" - select-poketypes-all: "SELECT id_pokemon, id_type FROM PokemonTypes" - select-max-id: "SELECT MAX(id) FROM Pokemons" - select-pokemon-named-arg: "SELECT id, name FROM Pokemons WHERE name=:name" - select-pokemon-order-arg: "SELECT id, name FROM Pokemons WHERE name=?" - insert-pokemon-named-arg: "INSERT INTO Pokemons(id, name) VALUES(:id, :name)" - insert-pokemon-order-arg: "INSERT INTO Pokemons(id, name) VALUES(?, ?)" - insert-pokemon-order-arg-rev: "INSERT INTO Pokemons(name, id) VALUES(?, ?)" - select-pokemon-by-id: "SELECT id, name FROM Pokemons WHERE id=?" - update-pokemon-named-arg: "UPDATE Pokemons SET name=:name WHERE id=:id" - update-pokemon-order-arg: "UPDATE Pokemons SET name=? WHERE id=?" - delete-pokemon-named-arg: "DELETE FROM Pokemons WHERE id=:id" - delete-pokemon-order-arg: "DELETE FROM Pokemons WHERE id=?" - delete-pokemon-full-named-arg: "DELETE FROM Pokemons WHERE name=:name AND id=:id" - delete-pokemon-full-order-arg: "DELETE FROM Pokemons WHERE name=? AND id=?" - select-pokemons-idrng-named-arg: "SELECT id, name FROM Pokemons WHERE id > :idmin AND id < :idmax" - select-pokemons-idrng-order-arg: "SELECT id, name FROM Pokemons WHERE id > ? AND id < ?" - select-pokemons-error-arg: "SELECT id, name FROM Pokemons WHERE id > :id AND name = ?" diff --git a/tests/integration/dbclient/app/src/main/resources/pgsql.yaml b/tests/integration/dbclient/app/src/main/resources/pgsql.yaml deleted file mode 100644 index 7f66eceac99..00000000000 --- a/tests/integration/dbclient/app/src/main/resources/pgsql.yaml +++ /dev/null @@ -1,61 +0,0 @@ -# -# Copyright (c) 2021, 2023 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. -# - -db: - source: jdbc - connection: - url: ${db.url} - username: ${db.user} - password: ${db.password} - health-check: - type: query - statement: "SELECT 0" - statements: - ping-query: "SELECT 0" - create-types: "CREATE TABLE Types (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(64) NOT NULL)" - create-pokemons: "CREATE TABLE Pokemons (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(64) NOT NULL)" - create-poketypes: "CREATE TABLE PokemonTypes (id_pokemon INTEGER NOT NULL, id_type INTEGER NOT NULL REFERENCES Types(id))" - drop-types: "DROP TABLE Types" - drop-pokemons: "DROP TABLE Pokemons" - drop-poketypes: "DROP TABLE PokemonTypes" - insert-type: "INSERT INTO Types(id, name) VALUES(?, ?)" - insert-pokemon: "INSERT INTO Pokemons(id, name) VALUES(?, ?)" - insert-poketype: "INSERT INTO PokemonTypes(id_pokemon, id_type) VALUES(?, ?)" - select-types: "SELECT id, name FROM Types" - select-pokemons: "SELECT id, name FROM Pokemons" - select-poketypes: "SELECT id_pokemon, id_type FROM PokemonTypes p WHERE id_pokemon = ?" - get-pokemon-by-id: "SELECT id, name FROM Pokemons WHERE id = ?" - get-pokemon-types: "SELECT t.id AS id, t.name AS name FROM Types t INNER JOIN PokemonTypes pt ON pt.id_type = t.id WHERE pt.id_pokemon = ?" - select-poketypes-all: "SELECT id_pokemon, id_type FROM PokemonTypes" - select-max-id: "SELECT MAX(id) FROM Pokemons" - select-pokemon-named-arg: "SELECT id, name FROM Pokemons WHERE name=:name" - select-pokemon-order-arg: "SELECT id, name FROM Pokemons WHERE name=?" - insert-pokemon-named-arg: "INSERT INTO Pokemons(id, name) VALUES(:id, :name)" - insert-pokemon-order-arg: "INSERT INTO Pokemons(id, name) VALUES(?, ?)" - insert-pokemon-order-arg-rev: "INSERT INTO Pokemons(name, id) VALUES(?, ?)" - select-pokemon-by-id: "SELECT id, name FROM Pokemons WHERE id=?" - update-pokemon-named-arg: "UPDATE Pokemons SET name=:name WHERE id=:id" - update-pokemon-order-arg: "UPDATE Pokemons SET name=? WHERE id=?" - delete-pokemon-named-arg: "DELETE FROM Pokemons WHERE id=:id" - delete-pokemon-order-arg: "DELETE FROM Pokemons WHERE id=?" - delete-pokemon-full-named-arg: "DELETE FROM Pokemons WHERE name=:name AND id=:id" - delete-pokemon-full-order-arg: "DELETE FROM Pokemons WHERE name=? AND id=?" - select-pokemons-idrng-named-arg: "SELECT id, name FROM Pokemons WHERE id > :idmin AND id < :idmax" - select-pokemons-idrng-order-arg: "SELECT id, name FROM Pokemons WHERE id > ? AND id < ?" - select-pokemons-error-arg: "SELECT id, name FROM Pokemons WHERE id > :id AND name = ?" - -test: - ping-dml: false diff --git a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/DbInit.java b/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/DbInit.java deleted file mode 100644 index e2d757ff393..00000000000 --- a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/DbInit.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app; - -import java.lang.System.Logger.Level; - -import io.helidon.tests.integration.harness.HelidonTestException; -import io.helidon.tests.integration.harness.JsonValues; -import io.helidon.tests.integration.harness.TestClient; -import io.helidon.tests.integration.harness.TestServiceClient; - -import jakarta.json.JsonObject; -import jakarta.json.JsonValue; - -/** - * Database initializer. - */ -class DbInit { - - private static final System.Logger LOGGER = System.getLogger(DbInit.class.getName()); - - private final TestServiceClient testClient; - - /** - * Create a new instance - * - * @param port port - */ - DbInit(int port) { - this.testClient = TestClient.builder() - .port(port) - .service("Init") - .build(); - } - - /** - * Invoke {@code /Init/testPing}. - */ - public void testPing() { - executeTest("testPing"); - } - - /** - * Invoke {@code /Init/testDropSchema}. - */ - public void dropSchema() { - try { - executeInit("testDropSchema"); - } catch (HelidonTestException ex) { - LOGGER.log(Level.INFO, "Remote database tables did not exist."); - } - } - - /** - * Invoke {@code /Init/testHealthCheck}. - */ - public void testHealthCheck() { - executeTest("testHealthCheck"); - } - - /** - * Invoke {@code /Init/testInitSchema}. - */ - public void initSchema() { - executeInit("testInitSchema"); - } - - /** - * Invoke {@code /Init/testInitTypes}. - */ - public void initTypes() { - executeInit("testInitTypes"); - } - - /** - * Invoke {@code /Init/testInitPokemons}. - */ - public void initPokemons() { - executeInit("testInitPokemons"); - } - - /** - * Invoke {@code /Init/testInitPokemonTypes}. - */ - public void initPokemonTypes() { - executeInit("testInitPokemonTypes"); - } - - private void executeTest(String testName) { - JsonObject data = testClient - .callServiceAndGetData(testName) - .asJsonObject(); - LogData.logJsonObject(Level.DEBUG, data); - } - - private void executeInit(String testName) { - JsonValue data = testClient - .callServiceAndGetData(testName); - Long count = JsonValues.asLong(data); - LOGGER.log(Level.DEBUG, () -> String.format("Rows modified: %d", count)); - } -} diff --git a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/LogData.java b/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/LogData.java deleted file mode 100644 index b33bd2bef4a..00000000000 --- a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/LogData.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app; - -import java.lang.System.Logger.Level; - -import jakarta.json.JsonArray; -import jakarta.json.JsonObject; - -/** - * JSON Data Log Helper. - */ -public class LogData { - - private static final System.Logger LOGGER = System.getLogger(LogData.class.getName()); - - /** - * Log JSON object in human-readable form. - * - * @param level logging level - * @param data data to log - */ - public static void logJsonObject(Level level, JsonObject data) { - LOGGER.log(level, () -> "JSON object:"); - if (data == null) { - LOGGER.log(level, " is null"); - return; - } - if (data.isEmpty()) { - LOGGER.log(level, " is empty"); - return; - } - data.forEach((key, value) - -> LOGGER.log(level, () -> String.format(" - %s: %s", key, value.toString()))); - } - - /** - * Log JSON array in human-readable form. - * - * @param level logging level - * @param data data to log - */ - public static void logJsonArray(Level level, JsonArray data) { - LOGGER.log(level, () -> String.format("JSON array: %s", data.toString())); - data.forEach(row -> { - switch (row.getValueType()) { - case OBJECT: - LOGGER.log(level, () -> " - Row:"); - row.asJsonObject().forEach((key, value) - -> LOGGER.log(level, () -> String.format(" - %s: %s", key, value.toString()))); - default: - LOGGER.log(level, () -> String.format(" - %s", row.toString())); - } - }); - } - -} diff --git a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/SuiteIT.java b/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/SuiteIT.java deleted file mode 100644 index bffd7cbd1be..00000000000 --- a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/SuiteIT.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2023 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.tests.integration.dbclient.app; - -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; -import java.util.Map; - -import io.helidon.logging.common.LogConfig; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientResponse; -import io.helidon.webserver.WebServer; -import io.helidon.tests.integration.harness.AfterSuite; -import io.helidon.tests.integration.harness.BeforeSuite; -import io.helidon.tests.integration.harness.HelidonProcessRunner; -import io.helidon.tests.integration.harness.HelidonProcessRunner.ExecType; - -import org.junit.platform.suite.api.IncludeClassNamePatterns; -import org.junit.platform.suite.api.SelectPackages; -import org.junit.platform.suite.api.Suite; - -@Suite -@SelectPackages("io.helidon.tests.integration.dbclient.app.tests") -@IncludeClassNamePatterns(".*IT") -class SuiteIT { - - private static final System.Logger LOGGER = System.getLogger(SuiteIT.class.getName()); - private static final int SLEEP_MILLIS = 250; - private static final int TIMEOUT = 60; - - @BeforeSuite - static Map setup() { - LogConfig.configureRuntime(); - LOGGER.log(System.Logger.Level.DEBUG, "Running test suite setup"); - - String appConfigProperty = System.getProperty("app.config"); - ExecType execType = ExecType.of(System.getProperty("app.execType", "classpath")); - WebServer[] server = new WebServer[1]; - HelidonProcessRunner processRunner = HelidonProcessRunner.builder() - .execType(execType) - .moduleName("io.helidon.tests.integration.dbclient.app") - .mainClass(Main.class.getName()) - .finalName("helidon-tests-integration-dbclient-app") - .args(new String[]{appConfigProperty}) - .inMemoryStartCommand(() -> server[0] = Main.startServer(appConfigProperty)) - .inMemoryStopCommand(() -> server[0].stop()) - .build() - .startApplication(); - - int serverPort = processRunner.port(); - - waitForDatabase(); - - // Call schema initialization services - if ("h2.yaml".equals(appConfigProperty)) { - DbInit dbInit = new DbInit(serverPort); - dbInit.dropSchema(); - dbInit.initSchema(); - dbInit.initTypes(); - dbInit.initPokemons(); - dbInit.initPokemonTypes(); - } - - return Map.of("processRunner", processRunner, "serverPort", serverPort); - } - - @AfterSuite - static void tearDown(int serverPort) { - LOGGER.log(System.Logger.Level.DEBUG, "Running test application close()"); - Http1Client testClient = Http1Client.builder() - .baseUri(String.format("http://localhost:%d", serverPort)) - .build(); - try (Http1ClientResponse response = testClient.get() - .path("/Exit") - .request()) { - LOGGER.log(System.Logger.Level.INFO, () -> String.format( - "Status: %s", - response.status())); - LOGGER.log(System.Logger.Level.INFO, () -> String.format( - "Response: %s", - response.entity().as(String.class))); - } - } - - @SuppressWarnings({"SleepWhileInLoop", "BusyWait"}) - private static void waitForDatabase() { - String user = System.getProperty("db.user"); - String password = System.getProperty("db.password"); - String url = System.getProperty("db.url"); - if (user == null) { - throw new IllegalStateException("Database user name was not set!"); - } - if (password == null) { - throw new IllegalStateException("Database user password was not set!"); - } - if (url == null) { - throw new IllegalStateException("Database URL was not set!"); - } - long endTm = 1000 * TIMEOUT + System.currentTimeMillis(); - while (true) { - try { - LOGGER.log(System.Logger.Level.DEBUG, () -> String.format( - "Connection check: user=%s password=%s url=%s", - user, password, url)); - Connection conn = DriverManager.getConnection(url, user, password); - closeConnection(conn); - return; - } catch (SQLException ex) { - LOGGER.log(System.Logger.Level.DEBUG, () -> String.format( - "Connection check: %s", ex.getMessage())); - if (System.currentTimeMillis() > endTm) { - throw new IllegalStateException(String.format( - "Database is not ready within %d seconds", TIMEOUT)); - } - try { - Thread.sleep(SLEEP_MILLIS); - } catch (InterruptedException ie) { - LOGGER.log(System.Logger.Level.WARNING, () -> String.format( - "Thread was interrupted: %s", ie.getMessage()), ie); - } - } - } - } - - private static void closeConnection(Connection connection) { - try { - connection.close(); - } catch (SQLException ex) { - LOGGER.log(System.Logger.Level.WARNING, () -> String.format( - "Could not close database connection: %s", ex.getMessage())); - } - } -} diff --git a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/VerifyData.java b/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/VerifyData.java deleted file mode 100644 index 0cd875961ca..00000000000 --- a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/VerifyData.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app; - -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; -import io.helidon.tests.integration.harness.TestClient; - -import jakarta.json.JsonObject; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; - -/** - * Test data verification helper methods. - */ -public class VerifyData { - - private static final String POKEMON_ID_KEY = "id"; - private static final String POKEMON_NAME_KEY = "name"; - - /** - * Verify that returned data contain single record with expected data. - * - * @param actual database query result to verify - * @param expected data to compare with - */ - public static void verifyPokemon(JsonObject actual, Pokemon expected) { - assertThat(actual, notNullValue()); - assertThat(actual.isEmpty(), is(false)); - Integer id = actual.getInt(POKEMON_ID_KEY); - String name = actual.getString(POKEMON_NAME_KEY); - assertThat(id, equalTo(expected.getId())); - assertThat(name, expected.getName().equals(name)); - } - - /** - * Verify that returned data contain single record with expected data. - * - * @param actual database query result to verify - * @param expected data to compare with - */ - public static void verifyPokemon(JsonObject actual, JsonObject expected) { - assertThat(actual, notNullValue()); - assertThat(expected, notNullValue()); - Integer id = actual.getInt(POKEMON_ID_KEY); - String name = actual.getString(POKEMON_NAME_KEY); - assertThat(id, equalTo(expected.getInt(POKEMON_ID_KEY))); - assertThat(name, equalTo(expected.getString(POKEMON_NAME_KEY))); - } - - /** - * Retrieve record as JSON object from remote web resource. - * - * @param testClient webclient used to access remote web resource - * @param id ID of record to retrieve - * @return JSON object - */ - public static JsonObject getPokemon(TestClient testClient, int id) { - return testClient.callServiceAndGetData( - "Verify", - "getPokemonById", - QueryParams.single(QueryParams.ID, String.valueOf(id))) - .asJsonObject(); - } - -} diff --git a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/FlowControlIT.java b/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/FlowControlIT.java deleted file mode 100644 index 9db515d4c2b..00000000000 --- a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/FlowControlIT.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.lang.System.Logger.Level; - -import io.helidon.tests.integration.dbclient.app.LogData; -import io.helidon.tests.integration.harness.TestClient; -import io.helidon.tests.integration.harness.TestServiceClient; - -import jakarta.json.JsonObject; -import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; - -/** - * Verify proper flow control handling in query processing. - */ -@TestMethodOrder(MethodOrderer.OrderAnnotation.class) -class FlowControlIT { - - private static final System.Logger LOGGER = System.getLogger(FlowControlIT.class.getName()); - - private final TestServiceClient testClient; - - FlowControlIT(int serverPort) { - this.testClient = TestClient.builder() - .port(serverPort) - .service("FlowControl") - .build(); - } - - private void executeTest(String testName) { - LOGGER.log(Level.DEBUG, () -> String.format("Running %s.%s on client", getClass().getSimpleName(), testName)); - JsonObject data = testClient - .callServiceAndGetData(testName) - .asJsonObject(); - LogData.logJsonObject(Level.DEBUG, data); - } - - /** - * Source data verification test. - */ - @Test - @Order(1) - void testSourceData() { - executeTest("testSourceData"); - } - - /** - * Flow control test. - */ - @Test - @Order(2) - void testFlowControl() { - executeTest("testFlowControl"); - } -} diff --git a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/HealthCheckIT.java b/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/HealthCheckIT.java deleted file mode 100644 index f85571945f2..00000000000 --- a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/HealthCheckIT.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.lang.System.Logger.Level; - -import io.helidon.health.HealthCheckResponse; -import io.helidon.tests.integration.dbclient.app.LogData; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; -import io.helidon.tests.integration.harness.TestClient; -import io.helidon.tests.integration.harness.TestServiceClient; - -import jakarta.json.JsonObject; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - -/** - * Test {@link io.helidon.dbclient.health.DbClientHealthCheck}. - */ -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class HealthCheckIT { - - private static final System.Logger LOGGER = System.getLogger(HealthCheckIT.class.getName()); - - private final TestServiceClient testClient; - private String dbType = null; - private boolean pingDml = true; - - HealthCheckIT(int serverPort) { - this.testClient = TestClient.builder() - .port(serverPort) - .service("HealthCheck") - .build(); - } - - @BeforeAll - void setup() { - JsonObject dbTypeValue = testClient - .callServiceAndGetData("Verify", "getDatabaseType", null) - .asJsonObject(); - LogData.logJsonObject(Level.DEBUG, dbTypeValue); - dbType = dbTypeValue.getString("type"); - JsonObject pingDmlValue = testClient - .callServiceAndGetData( - "Verify", "getConfigParam", - QueryParams.single(QueryParams.NAME, "test.ping-dml")) - .asJsonObject(); - LogData.logJsonObject(Level.DEBUG, pingDmlValue); - if (pingDmlValue.containsKey("config")) { - pingDml = Boolean.parseBoolean(pingDmlValue.getString("config")); - } - } - - /** - * Verify health check implementation with default settings. - */ - @Test - void testHealthCheck() { - JsonObject data = testClient - .callServiceAndGetData("testHealthCheck") - .asJsonObject(); - LogData.logJsonObject(Level.DEBUG, data); - assertThat(data.getString("status"), equalTo(HealthCheckResponse.Status.UP.name())); - } - - /** - * Verify health check implementation with builder and custom name. - */ - @Test - void testHealthCheckWithName() { - String hcName = "TestHC"; - JsonObject data = testClient - .callServiceAndGetData( - "testHealthCheckWithName", - QueryParams.single(QueryParams.NAME, hcName)) - .asJsonObject(); - LogData.logJsonObject(Level.DEBUG, data); - assertThat(data.getString("status"), equalTo(HealthCheckResponse.Status.UP.name())); - assertThat(data.getString("name"), equalTo(hcName)); - } - - /** - * Verify health check implementation using custom DML named statement. - */ - @Test - void testHealthCheckWithCustomNamedDML() { - if (!pingDml) { - LOGGER.log(Level.INFO, () -> String.format("Database %s does not support DML ping, skipping this test", dbType)); - return; - } - JsonObject data = testClient - .callServiceAndGetData("testHealthCheckWithCustomNamedDML") - .asJsonObject(); - LogData.logJsonObject(Level.DEBUG, data); - assertThat(data.getString("status"), equalTo(HealthCheckResponse.Status.UP.name())); - } - - /** - * Verify health check implementation using custom DML statement. - */ - @Test - void testHealthCheckWithCustomDML() { - if (!pingDml) { - LOGGER.log(Level.DEBUG, () -> String.format("Database %s does not support DML ping, skipping this test", dbType)); - return; - } - JsonObject data = testClient - .callServiceAndGetData("testHealthCheckWithCustomDML") - .asJsonObject(); - LogData.logJsonObject(Level.DEBUG, data); - assertThat(data.getString("status"), equalTo(HealthCheckResponse.Status.UP.name())); - } - - /** - * Verify health check implementation using custom query named statement. - */ - @Test - void testHealthCheckWithCustomNamedQuery() { - JsonObject data = testClient - .callServiceAndGetData("testHealthCheckWithCustomNamedQuery") - .asJsonObject(); - LogData.logJsonObject(Level.DEBUG, data); - assertThat(data.getString("status"), equalTo(HealthCheckResponse.Status.UP.name())); - } - - /** - * Verify health check implementation using custom query statement. - */ - @Test - void testHealthCheckWithCustomQuery() { - JsonObject data = testClient - .callServiceAndGetData("testHealthCheckWithCustomQuery") - .asJsonObject(); - LogData.logJsonObject(Level.DEBUG, data); - assertThat(data.getString("status"), equalTo(HealthCheckResponse.Status.UP.name())); - } -} diff --git a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/InterceptorIT.java b/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/InterceptorIT.java deleted file mode 100644 index 872988740c5..00000000000 --- a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/InterceptorIT.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import io.helidon.tests.integration.harness.TestClient; -import io.helidon.tests.integration.harness.TestServiceClient; - -import org.junit.jupiter.api.Test; - -/** - * Test {@link io.helidon.dbclient.DbClientService}. - */ -class InterceptorIT { - - private static final System.Logger LOGGER = System.getLogger(InterceptorIT.class.getName()); - - private final TestServiceClient testClient; - - InterceptorIT(int serverPort) { - this.testClient = TestClient.builder() - .port(serverPort) - .service("Interceptor") - .build(); - } - - /** - * Check that statement interceptor was called before statement execution. - */ - @Test - void testStatementInterceptor() { - LOGGER.log(System.Logger.Level.DEBUG, () -> String.format("Running %s.%s on client", getClass().getSimpleName(), "testStatementInterceptor")); - testClient.callServiceAndGetData("testStatementInterceptor"); - } -} diff --git a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/MapperIT.java b/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/MapperIT.java deleted file mode 100644 index b981f9a05b8..00000000000 --- a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/MapperIT.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.lang.System.Logger.Level; - -import io.helidon.tests.integration.dbclient.app.LogData; -import io.helidon.tests.integration.dbclient.app.VerifyData; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; -import io.helidon.tests.integration.harness.JsonValues; -import io.helidon.tests.integration.harness.TestClient; -import io.helidon.tests.integration.harness.TestServiceClient; - -import jakarta.json.JsonArray; -import jakarta.json.JsonObject; -import jakarta.json.JsonValue; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - -/** - * Verify mapping interface. - */ -class MapperIT { - - private static final System.Logger LOGGER = System.getLogger(MapperIT.class.getName()); - - private final TestServiceClient testClient; - - MapperIT(int serverPort) { - this.testClient = TestClient.builder() - .port(serverPort) - .service("Mapper") - .build(); - } - - /** - * Verify insertion using indexed mapping. - */ - @Test - void testInsertWithOrderMapping() { - executeInsertTest("testInsertWithOrderMapping", 103); - } - - /** - * Verify insertion using named mapping. - */ - @Test - void testInsertWithNamedMapping() { - executeInsertTest("testInsertWithNamedMapping", 104); - } - - /** - * Verify update using indexed mapping. - */ - @Test - void testUpdateWithOrderMapping() { - executeUpdateTest("testUpdateWithOrderMapping", 99, "Masquerain"); - } - - /** - * Verify update using named mapping. - */ - @Test - void testUpdateWithNamedMapping() { - executeUpdateTest("testUpdateWithNamedMapping", 100, "Moltres"); - } - - /** - * Verify delete using indexed mapping. - */ - @Test - void testDeleteWithOrderMapping() { - executeDeleteTest("testDeleteWithOrderMapping", 101); - } - - /** - * Verify delete using named mapping. - */ - @Test - void testDeleteWithNamedMapping() { - executeDeleteTest("testDeleteWithNamedMapping", 102); - } - - // Query and Get calls are here just once so no common executor code is needed. - - /** - * Verify query as a result using mapping. - */ - @Test - void testQueryWithMapping() { - Pokemon pokemon = Pokemon.POKEMONS.get(1); - JsonArray data = testClient - .callServiceAndGetData( - "testQueryWithMapping", - QueryParams.single(QueryParams.NAME, pokemon.getName())) - .asJsonArray(); - LogData.logJsonArray(Level.DEBUG, data); - assertThat(data.size(), equalTo(1)); - VerifyData.verifyPokemon(data.getJsonObject(0), pokemon); - } - - /** - * Verify get as a result using mapping. - */ - @Test - void testGetWithMapping() { - Pokemon pokemon = Pokemon.POKEMONS.get(2); - JsonObject data = testClient - .callServiceAndGetData( - "testGetWithMapping", - QueryParams.single(QueryParams.NAME, pokemon.getName())) - .asJsonObject(); - LogData.logJsonObject(Level.DEBUG, data); - VerifyData.verifyPokemon(data, pokemon); - } - - private void executeInsertTest(String testName, int id) { - LOGGER.log(Level.DEBUG, () -> String.format("Running %s.%s on client", getClass().getSimpleName(), testName)); - JsonObject data = testClient - .callServiceAndGetData( - testName, - QueryParams.single(QueryParams.ID, String.valueOf(id))) - .asJsonObject(); - LogData.logJsonObject(Level.DEBUG, data); - JsonObject pokemonData = VerifyData.getPokemon(testClient, id); - LogData.logJsonObject(Level.DEBUG, pokemonData); - VerifyData.verifyPokemon(pokemonData, data); - } - - private void executeUpdateTest(String testName, int id, String newName) { - LOGGER.log(Level.DEBUG, () -> String.format("Running MapperIT.%s on client", testName)); - Pokemon pokemon = Pokemon.POKEMONS.get(id); - Pokemon updatedPokemon = new Pokemon(pokemon.getId(), newName, pokemon.getTypes()); - JsonValue data = testClient - .callServiceAndGetData( - testName, - QueryParams.builder() - .add(QueryParams.NAME, newName) - .add(QueryParams.ID, String.valueOf(id)) - .build()); - Long count = JsonValues.asLong(data); - LOGGER.log(Level.DEBUG, () -> String.format("Rows updated: %d", count)); - JsonObject pokemonData = VerifyData.getPokemon(testClient, pokemon.getId()); - LogData.logJsonObject(Level.DEBUG, pokemonData); - assertThat(count, equalTo(1L)); - VerifyData.verifyPokemon(pokemonData, updatedPokemon); - } - - private void executeDeleteTest(String testName, int id) { - LOGGER.log(Level.DEBUG, () -> String.format("Running MapperIT.%s on client", testName)); - JsonValue data = testClient - .callServiceAndGetData( - testName, - QueryParams.single(QueryParams.ID, String.valueOf(id))); - Long count = JsonValues.asLong(data); - LOGGER.log(Level.DEBUG, () -> String.format("Rows deleted: %d", count)); - JsonObject pokemonData = VerifyData.getPokemon(testClient, id); - LogData.logJsonObject(Level.DEBUG, pokemonData); - assertThat(count, equalTo(1L)); - assertThat(pokemonData.isEmpty(), equalTo(true)); - } -} diff --git a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/ServerMetricsCheckIT.java b/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/ServerMetricsCheckIT.java deleted file mode 100644 index 3b1c05d4c16..00000000000 --- a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/ServerMetricsCheckIT.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; -import io.helidon.tests.integration.harness.TestClient; - -import io.helidon.tests.integration.harness.TestServiceClient; -import jakarta.json.JsonObject; -import jakarta.json.JsonValue; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.notNullValue; - -/** - * Test JDBC metrics. - */ -class ServerMetricsCheckIT { - - private static final System.Logger LOGGER = System.getLogger(ServerMetricsCheckIT.class.getName()); - - private final TestClient testClient; - - ServerMetricsCheckIT(int serverPort) { - this.testClient = TestServiceClient.builder() - .port(serverPort) - .build(); - } - - /** - * Read and check Database Client metrics from Helidon Web Server. - * - */ - @Test - void testHttpMetrics() { - LOGGER.log(System.Logger.Level.DEBUG, () -> String.format("Running %s.%s on client", getClass().getSimpleName(), "testHttpMetrics")); - - // Call select-pokemon-named-arg query to initialize counter - testClient.callServiceAndGetData( - "SimpleGet", - "testCreateNamedGetStrNamedArgs", - QueryParams.single(QueryParams.NAME, Pokemon.POKEMONS.get(1).getName())); - // Call select-pokemon-order-arg query to initialize counter - testClient.callServiceAndGetData( - "SimpleGet", - "testCreateNamedGetStrOrderArgs", - QueryParams.single(QueryParams.NAME, Pokemon.POKEMONS.get(2).getName())); - - JsonObject application; - application = testClient.callServiceAndGetRawData("observe/metrics", "application"); - assertThat(application, notNullValue()); - assertThat(application.getValueType(), equalTo(JsonValue.ValueType.OBJECT)); - assertThat(application.size(), greaterThan(0)); - assertThat(application.containsKey("db.counter.select-pokemon-named-arg"), equalTo(true)); - assertThat(application.containsKey("db.counter.select-pokemon-order-arg"), equalTo(true)); - assertThat(application.containsKey("db.counter.insert-pokemon"), equalTo(true)); - int selectPokemons = application.getInt("db.counter.select-pokemon-named-arg"); - int insertPokemons = application.getInt("db.counter.insert-pokemon"); - assertThat(selectPokemons, greaterThan(0)); - assertThat(insertPokemons, greaterThan(0)); - assertThat(application.containsKey("db.timer.select-pokemon-named-arg"), equalTo(true)); - assertThat(application.containsKey("db.timer.select-pokemon-named-arg"), equalTo(true)); - JsonObject insertTimer = application.getJsonObject("db.timer.select-pokemon-named-arg"); - assertThat(insertTimer.containsKey("count"), equalTo(true)); - assertThat(insertTimer.containsKey("max"), equalTo(true)); - int timerCount = insertTimer.getInt("count"); - assertThat(timerCount, greaterThan(0)); - } -} diff --git a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/SimpleDeleteIT.java b/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/SimpleDeleteIT.java deleted file mode 100644 index c1722a72537..00000000000 --- a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/SimpleDeleteIT.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.lang.System.Logger.Level; - -import io.helidon.tests.integration.dbclient.app.LogData; -import io.helidon.tests.integration.dbclient.app.VerifyData; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; -import io.helidon.tests.integration.harness.JsonValues; -import io.helidon.tests.integration.harness.TestClient; -import io.helidon.tests.integration.harness.TestServiceClient; - -import jakarta.json.JsonObject; -import jakarta.json.JsonValue; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - -/** - * Test simple delete statements. - */ -class SimpleDeleteIT { - - private static final System.Logger LOGGER = System.getLogger(SimpleDeleteIT.class.getName()); - - private final TestServiceClient testClient; - - SimpleDeleteIT(int serverPort) { - this.testClient = TestClient.builder() - .port(serverPort) - .service("SimpleDelete") - .build(); - } - - private void executeTest(String testName, int id) { - LOGGER.log(Level.DEBUG, () -> String.format("Running %s.%s on client", getClass().getSimpleName(), testName)); - JsonValue data = testClient - .callServiceAndGetData( - testName, - QueryParams.single(QueryParams.ID, String.valueOf(id))); - Long count = JsonValues.asLong(data); - LOGGER.log(Level.DEBUG, () -> String.format("Rows deleted: %d", count)); - JsonObject pokemonData = VerifyData.getPokemon(testClient, id); - LogData.logJsonObject(Level.DEBUG, pokemonData); - assertThat(count, equalTo(1L)); - assertThat(pokemonData.isEmpty(), equalTo(true)); - } - - /** - * Verify {@code createNamedDelete(String, String)} API method with ordered parameters. - */ - @Test - void testCreateNamedDeleteStrStrOrderArgs() { - executeTest("testCreateNamedDeleteStrStrOrderArgs", 15); - } - - /** - * Verify {@code createNamedDelete(String)} API method with named parameters. - */ - @Test - void testCreateNamedDeleteStrNamedArgs() { - executeTest("testCreateNamedDeleteStrNamedArgs", 16); - } - - /** - * Verify {@code createNamedDelete(String)} API method with ordered parameters. - */ - @Test - void testCreateNamedDeleteStrOrderArgs() { - executeTest("testCreateNamedDeleteStrOrderArgs", 17); - } - - /** - * Verify {@code createDelete(String)} API method with named parameters. - */ - @Test - void testCreateDeleteNamedArgs() { - executeTest("testCreateDeleteNamedArgs", 18); - } - - /** - * Verify {@code createDelete(String)} API method with ordered parameters. - */ - @Test - void testCreateDeleteOrderArgs() { - executeTest("testCreateDeleteOrderArgs", 19); - } - - /** - * Verify {@code namedDelete(String)} API method with ordered parameters. - */ - @Test - void testNamedDeleteOrderArgs() { - executeTest("testNamedDeleteOrderArgs", 20); - } - - /** - * Verify {@code delete(String)} API method with ordered parameters. - */ - @Test - void testDeleteOrderArgs() { - executeTest("testDeleteOrderArgs", 21); - } - - // DML delete - - /** - * Verify {@code createNamedDmlStatement(String, String)} API method with delete with ordered parameters. - */ - @Test - void testCreateNamedDmlWithDeleteStrStrOrderArgs() { - executeTest("testCreateNamedDmlWithDeleteStrStrOrderArgs", 36); - } - - /** - * Verify {@code createNamedDmlStatement(String)} API method with delete with named parameters. - */ - @Test - void testCreateNamedDmlWithDeleteStrNamedArgs() { - executeTest("testCreateNamedDmlWithDeleteStrNamedArgs", 37); - } - - /** - * Verify {@code createNamedDmlStatement(String)} API method with delete with ordered parameters. - */ - @Test - void testCreateNamedDmlWithDeleteStrOrderArgs() { - executeTest("testCreateNamedDmlWithDeleteStrOrderArgs", 38); - } - - /** - * Verify {@code createDmlStatement(String)} API method with delete with named parameters. - */ - @Test - void testCreateDmlWithDeleteNamedArgs() { - executeTest("testCreateDmlWithDeleteNamedArgs", 39); - } - - /** - * Verify {@code createDmlStatement(String)} API method with delete with ordered parameters. - */ - @Test - void testCreateDmlWithDeleteOrderArgs() { - executeTest("testCreateDmlWithDeleteOrderArgs", 40); - } - - /** - * Verify {@code namedDml(String)} API method with delete with ordered parameters. - */ - @Test - void testNamedDmlWithDeleteOrderArgs() { - executeTest("testNamedDmlWithDeleteOrderArgs", 41); - } - - /** - * Verify {@code dml(String)} API method with delete with ordered parameters. - */ - @Test - void testDmlWithDeleteOrderArgs() { - executeTest("testDmlWithDeleteOrderArgs", 42); - } - -} diff --git a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/SimpleGetIT.java b/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/SimpleGetIT.java deleted file mode 100644 index 0fb26a5199f..00000000000 --- a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/SimpleGetIT.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.lang.System.Logger.Level; - -import io.helidon.tests.integration.dbclient.app.LogData; -import io.helidon.tests.integration.dbclient.app.VerifyData; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; -import io.helidon.tests.integration.harness.TestClient; -import io.helidon.tests.integration.harness.TestServiceClient; - -import jakarta.json.JsonObject; -import org.junit.jupiter.api.Test; - -/** - * Test simple get statements. - */ -class SimpleGetIT { - - private static final System.Logger LOGGER = System.getLogger(SimpleGetIT.class.getName()); - - private final TestServiceClient testClient; - - SimpleGetIT(int serverPort) { - this.testClient = TestClient.builder() - .port(serverPort) - .service("SimpleGet") - .build(); - } - - void executeTest(String testName, Pokemon pokemon) { - LOGGER.log(Level.DEBUG, () -> String.format("Running %s.%s on client", getClass().getSimpleName(), testName)); - JsonObject data = testClient - .callServiceAndGetData( - testName, - QueryParams.single(QueryParams.NAME, pokemon.getName())) - .asJsonObject(); - LogData.logJsonObject(Level.DEBUG, data); - VerifyData.verifyPokemon(data, pokemon); - } - - /** - * Verify {@code createNamedGet(String, String)} API method with named - * parameters. - */ - @Test - void testCreateNamedGetStrStrNamedArgs() { - executeTest("testCreateNamedGetStrStrNamedArgs", Pokemon.POKEMONS.get(1)); - } - - /** - * Verify {@code createNamedGet(String)} API method with named parameters. - */ - @Test - void testCreateNamedGetStrNamedArgs() { - executeTest("testCreateNamedGetStrNamedArgs", Pokemon.POKEMONS.get(2)); - } - - /** - * Verify {@code createNamedGet(String)} API method with ordered parameters. - */ - @Test - void testCreateNamedGetStrOrderArgs() { - executeTest("testCreateNamedGetStrOrderArgs", Pokemon.POKEMONS.get(3)); - } - - /** - * Verify {@code createGet(String)} API method with named parameters. - */ - @Test - void testCreateGetNamedArgs() { - executeTest("testCreateGetNamedArgs", Pokemon.POKEMONS.get(4)); - } - - /** - * Verify {@code createGet(String)} API method with ordered parameters. - */ - @Test - void testCreateGetOrderArgs() { - executeTest("testCreateGetOrderArgs", Pokemon.POKEMONS.get(5)); - } - - /** - * Verify {@code namedGet(String)} API method with ordered parameters passed - * directly to the {@code query} method. - */ - @Test - void testNamedGetStrOrderArgs() { - executeTest("testNamedGetStrOrderArgs", Pokemon.POKEMONS.get(6)); - } - - /** - * Verify {@code get(String)} API method with ordered parameters passed - * directly to the {@code query} method. - */ - @Test - void testGetStrOrderArgs() { - executeTest("testGetStrOrderArgs", Pokemon.POKEMONS.get(7)); - } - -} diff --git a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/SimpleInsertIT.java b/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/SimpleInsertIT.java deleted file mode 100644 index 097cbf8ad50..00000000000 --- a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/SimpleInsertIT.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.lang.System.Logger.Level; - -import io.helidon.tests.integration.dbclient.app.LogData; -import io.helidon.tests.integration.dbclient.app.VerifyData; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; -import io.helidon.tests.integration.harness.TestClient; -import io.helidon.tests.integration.harness.TestServiceClient; - -import jakarta.json.JsonObject; -import org.junit.jupiter.api.Test; - -/** - * Test simple insert statements. - */ -class SimpleInsertIT { - - private static final System.Logger LOGGER = System.getLogger(SimpleInsertIT.class.getName()); - - private final TestServiceClient testClient; - - SimpleInsertIT(int serverPort) { - this.testClient = TestClient.builder() - .port(serverPort) - .service("SimpleInsert") - .build(); - } - - private void executeTest(String testName, int id) { - LOGGER.log(Level.DEBUG, () -> String.format("Running %s.%s on client", getClass().getSimpleName(), testName)); - JsonObject data = testClient.callServiceAndGetData( - testName, - QueryParams.single(QueryParams.ID, String.valueOf(id))) - .asJsonObject(); - LogData.logJsonObject(Level.DEBUG, data); - JsonObject pokemonData = VerifyData.getPokemon(testClient, id); - LogData.logJsonObject(Level.DEBUG, pokemonData); - VerifyData.verifyPokemon(pokemonData, data); - } - - /** - * Verify {@code createNamedInsert(String, String)} API method with named parameters. - */ - @Test - void testCreateNamedInsertStrStrNamedArgs() { - executeTest("testCreateNamedInsertStrStrNamedArgs", 22); - } - - /** - * Verify {@code createNamedInsert(String)} API method with named parameters. - */ - @Test - void testCreateNamedInsertStrNamedArgs() { - executeTest("testCreateNamedInsertStrNamedArgs", 23); - } - - /** - * Verify {@code createNamedInsert(String)} API method with ordered parameters. - */ - @Test - void testCreateNamedInsertStrOrderArgs() { - executeTest("testCreateNamedInsertStrOrderArgs", 24); - } - - /** - * Verify {@code createInsert(String)} API method with named parameters. - */ - @Test - void testCreateInsertNamedArgs() { - executeTest("testCreateInsertNamedArgs", 25); - } - - /** - * Verify {@code createInsert(String)} API method with ordered parameters. - */ - @Test - void testCreateInsertOrderArgs() { - executeTest("testCreateInsertOrderArgs", 26); - } - - /** - * Verify {@code namedInsert(String)} API method with ordered parameters passed directly to the {@code insert} method. - */ - @Test - void testNamedInsertOrderArgs() { - executeTest("testNamedInsertOrderArgs", 27); - } - - /** - * Verify {@code insert(String)} API method with ordered parameters passed directly to the {@code insert} method. - */ - @Test - void testInsertOrderArgs() { - executeTest("testInsertOrderArgs", 28); - } - - // DML insert - - /** - * Verify {@code createNamedDmlStatement(String, String)} API method with insert with named parameters. - */ - @Test - void testCreateNamedDmlWithInsertStrStrNamedArgs() { - executeTest("testCreateNamedDmlWithInsertStrStrNamedArgs", 43); - } - - /** - * Verify {@code createNamedDmlStatement(String)} API method with insert with named parameters. - */ - @Test - void testCreateNamedDmlWithInsertStrNamedArgs() { - executeTest("testCreateNamedDmlWithInsertStrNamedArgs", 44); - } - - /** - * Verify {@code createNamedDmlStatement(String)} API method with insert with ordered parameters. - */ - @Test - void testCreateNamedDmlWithInsertStrOrderArgs() { - executeTest("testCreateNamedDmlWithInsertStrOrderArgs", 45); - } - - /** - * Verify {@code createDmlStatement(String)} API method with insert with named parameters. - */ - @Test - void testCreateDmlWithInsertNamedArgs() { - executeTest("testCreateDmlWithInsertNamedArgs", 46); - } - - /** - * Verify {@code createDmlStatement(String)} API method with insert with ordered parameters. - */ - @Test - void testCreateDmlWithInsertOrderArgs() { - executeTest("testCreateDmlWithInsertOrderArgs", 47); - } - - /** - * Verify {@code namedDml(String)} API method with insert with ordered parameters passed directly - * to the {@code insert} method. - */ - @Test - void testNamedDmlWithInsertOrderArgs() { - executeTest("testNamedDmlWithInsertOrderArgs", 48); - } - - /** - * Verify {@code dml(String)} API method with insert with ordered parameters passed directly - * to the {@code insert} method. - */ - @Test - void testDmlWithInsertOrderArgs() { - executeTest("testDmlWithInsertOrderArgs", 49); - } - -} diff --git a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/SimpleQueriesIT.java b/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/SimpleQueriesIT.java deleted file mode 100644 index b696716fcf9..00000000000 --- a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/SimpleQueriesIT.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.lang.System.Logger.Level; - -import io.helidon.tests.integration.dbclient.app.LogData; -import io.helidon.tests.integration.dbclient.app.VerifyData; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; -import io.helidon.tests.integration.harness.TestClient; -import io.helidon.tests.integration.harness.TestServiceClient; - -import jakarta.json.JsonArray; -import org.hamcrest.Matchers; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Test simple query statements. - */ -class SimpleQueriesIT { - - private static final System.Logger LOGGER = System.getLogger(SimpleQueriesIT.class.getName()); - - private final TestServiceClient testClient; - - SimpleQueriesIT(int serverPort) { - this.testClient = TestClient.builder() - .port(serverPort) - .service("SimpleQuery") - .build(); - } - - private void executeTest(String testName, Pokemon pokemon) { - LOGGER.log(Level.DEBUG, () -> String.format("Running %s.%s on client", getClass().getSimpleName(), testName)); - JsonArray data = testClient - .callServiceAndGetData( - testName, - QueryParams.single(QueryParams.NAME, pokemon.getName())) - .asJsonArray(); - LogData.logJsonArray(Level.DEBUG, data); - assertThat(data.size(), Matchers.equalTo(1)); - VerifyData.verifyPokemon(data.getJsonObject(0), pokemon); - } - - /** - * Verify {@code createNamedQuery(String, String)} API method with ordered parameters. - */ - @Test - void testCreateNamedQueryStrStrOrderArgs() { - executeTest("testCreateNamedQueryStrStrOrderArgs", Pokemon.POKEMONS.get(1)); - } - - /** - * Verify {@code createNamedQuery(String)} API method with named parameters. - */ - @Test - void testCreateNamedQueryStrNamedArgs() { - executeTest("testCreateNamedQueryStrNamedArgs", Pokemon.POKEMONS.get(2)); - } - - /** - * Verify {@code createNamedQuery(String)} API method with ordered parameters. - */ - @Test - void testCreateNamedQueryStrOrderArgs() { - executeTest("testCreateNamedQueryStrOrderArgs", Pokemon.POKEMONS.get(3)); - } - - /** - * Verify {@code createQuery(String)} API method with named parameters. - */ - @Test - void testCreateQueryNamedArgs() { - executeTest("testCreateQueryNamedArgs", Pokemon.POKEMONS.get(4)); - } - - /** - * Verify {@code createQuery(String)} API method with ordered parameters. - */ - @Test - void testCreateQueryOrderArgs() { - executeTest("testCreateQueryOrderArgs", Pokemon.POKEMONS.get(5)); - } - - /** - * Verify {@code namedQuery(String)} API method with ordered parameters passed directly to the {@code namedQuery} method. - */ - @Test - void testNamedQueryOrderArgs() { - executeTest("testNamedQueryOrderArgs", Pokemon.POKEMONS.get(6)); - } - - /** - * Verify {@code query(String)} API method with ordered parameters passed directly to the {@code query} method. - */ - @Test - void testQueryOrderArgs() { - executeTest("testQueryOrderArgs", Pokemon.POKEMONS.get(7)); - } - -} diff --git a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/SimpleUpdateIT.java b/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/SimpleUpdateIT.java deleted file mode 100644 index 6bf64bd5373..00000000000 --- a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/SimpleUpdateIT.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.lang.System.Logger.Level; - -import io.helidon.tests.integration.dbclient.app.LogData; -import io.helidon.tests.integration.dbclient.app.VerifyData; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; -import io.helidon.tests.integration.harness.JsonValues; -import io.helidon.tests.integration.harness.TestClient; -import io.helidon.tests.integration.harness.TestServiceClient; - -import jakarta.json.JsonObject; -import jakarta.json.JsonValue; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - -/** - * Test simple update statements. - */ -class SimpleUpdateIT { - - private static final System.Logger LOGGER = System.getLogger(SimpleUpdateIT.class.getName()); - - private final TestServiceClient testClient; - - SimpleUpdateIT(int serverPort) { - this.testClient = TestClient.builder() - .port(serverPort) - .service("SimpleUpdate") - .build(); - } - - private void executeTest(String testName, int id, String newName) { - LOGGER.log(Level.DEBUG, () -> String.format("Running %s.%s on client", getClass().getSimpleName(), testName)); - Pokemon pokemon = Pokemon.POKEMONS.get(id); - Pokemon updatedPokemon = new Pokemon(pokemon.getId(), newName, pokemon.getTypes()); - JsonValue data = testClient.callServiceAndGetData( - testName, - QueryParams.builder() - .add(QueryParams.NAME, newName) - .add(QueryParams.ID, String.valueOf(id)) - .build()); - Long count = JsonValues.asLong(data); - LOGGER.log(Level.DEBUG, () -> String.format("Rows updated: %d", count)); - JsonObject pokemonData = VerifyData.getPokemon(testClient, pokemon.getId()); - LogData.logJsonObject(Level.DEBUG, pokemonData); - assertThat(count, equalTo(1L)); - VerifyData.verifyPokemon(pokemonData, updatedPokemon); - } - - /** - * Verify {@code createNamedUpdate(String, String)} API method with ordered parameters. - */ - @Test - void testCreateNamedUpdateStrStrNamedArgs() { - executeTest("testCreateNamedUpdateStrStrNamedArgs", 8, "Fearow"); - } - - /** - * Verify {@code createNamedUpdate(String)} API method with named parameters. - */ - @Test - void testCreateNamedUpdateStrNamedArgs() { - executeTest("testCreateNamedUpdateStrNamedArgs", 9, "Spearow"); - } - - /** - * Verify {@code createNamedUpdate(String, String)} API method with ordered parameters. - */ - @Test - void testCreateNamedUpdateStrOrderArgs() { - executeTest("testCreateNamedUpdateStrOrderArgs", 10, "Arbok"); - } - - /** - * Verify {@code createUpdate(String)} API method with named parameters. - */ - @Test - void testCreateUpdateNamedArgs() { - executeTest("testCreateUpdateNamedArgs", 11, "Ekans"); - } - - - /** - * Verify {@code createUpdate(String)} API method with named parameters. - */ - @Test - void testCreateUpdateOrderArgs() { - executeTest("testCreateUpdateOrderArgs", 12, "Diglett"); - } - - /** - * Verify {@code namedUpdate(String, String)} API method with ordered parameters. - */ - @Test - void testNamedUpdateNamedArgs() { - executeTest("testNamedUpdateNamedArgs", 13, "Sandshrew"); - } - - /** - * Verify {@code update(String)} API method with named parameters. - */ - @Test - void testUpdateOrderArgs() { - executeTest("testUpdateOrderArgs", 14, "Sandslash"); - } - - // DML update - - /** - * Verify {@code createNamedDmlStatement(String, String)} API method with update with named parameters. - */ - @Test - void testCreateNamedDmlWithUpdateStrStrNamedArgs() { - executeTest("testCreateNamedDmlWithUpdateStrStrNamedArgs", 29, "Prinplup"); - } - - /** - * Verify {@code createNamedDmlStatement(String)} API method with update with named parameters. - */ - @Test - void testCreateNamedDmlWithUpdateStrNamedArgs() { - executeTest("testCreateNamedDmlWithUpdateStrNamedArgs", 30, "Empoleon"); - } - - /** - * Verify {@code createNamedDmlStatement(String)} API method with update with ordered parameters. - */ - @Test - void testCreateNamedDmlWithUpdateStrOrderArgs() { - executeTest("testCreateNamedDmlWithUpdateStrOrderArgs", 31, "Piplup"); - } - - /** - * Verify {@code createDmlStatement(String)} API method with update with named parameters. - */ - @Test - void testCreateDmlWithUpdateNamedArgs() { - executeTest("testCreateDmlWithUpdateNamedArgs", 32, "Starmie"); - } - - /** - * Verify {@code createDmlStatement(String)} API method with update with ordered parameters. - */ - @Test - void testCreateDmlWithUpdateOrderArgs() { - executeTest("testCreateDmlWithUpdateOrderArgs", 33, "Staryu"); - } - - /** - * Verify {@code namedDml(String)} API method with update with ordered parameters passed directly - * to the {@code insert} method. - */ - @Test - void testNamedDmlWithUpdateOrderArgs() { - executeTest("testNamedDmlWithUpdateOrderArgs", 34, "Seadra"); - } - - /** - * Verify {@code dml(String)} API method with update with ordered parameters passed directly - * to the {@code insert} method. - */ - @Test - void testDmlWithUpdateOrderArgs() { - executeTest("testDmlWithUpdateOrderArgs", 35, "Horsea"); - } - -} diff --git a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/StatementDmlIT.java b/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/StatementDmlIT.java deleted file mode 100644 index e4de9d1cd14..00000000000 --- a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/StatementDmlIT.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.lang.System.Logger.Level; - -import io.helidon.tests.integration.dbclient.app.LogData; -import io.helidon.tests.integration.dbclient.app.VerifyData; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; -import io.helidon.tests.integration.harness.JsonValues; -import io.helidon.tests.integration.harness.TestClient; -import io.helidon.tests.integration.harness.TestServiceClient; - -import jakarta.json.JsonObject; -import jakarta.json.JsonValue; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - -/** - * Test DML statements. - */ -class StatementDmlIT { - - private static final System.Logger LOGGER = System.getLogger(StatementDmlIT.class.getName()); - - private final TestServiceClient testClient; - - StatementDmlIT(int serverPort) { - this.testClient = TestClient.builder() - .port(serverPort) - .service("StatementDml") - .build(); - } - - private void executeTest(String testName, int id, String newName) { - LOGGER.log(Level.DEBUG, () -> String.format("Running %s.%s on client", getClass().getSimpleName(), testName)); - Pokemon pokemon = Pokemon.POKEMONS.get(id); - Pokemon updatedPokemon = new Pokemon(pokemon.getId(), newName, pokemon.getTypes()); - JsonValue data = testClient - .callServiceAndGetData( - testName, - QueryParams.builder() - .add(QueryParams.NAME, newName) - .add(QueryParams.ID, String.valueOf(id)) - .build()); - Long count = JsonValues.asLong(data); - LOGGER.log(Level.DEBUG, () -> String.format("Rows modified: %d", count)); - JsonObject pokemonData = VerifyData.getPokemon(testClient, pokemon.getId()); - LogData.logJsonObject(Level.DEBUG, pokemonData); - assertThat(count, equalTo(1L)); - VerifyData.verifyPokemon(pokemonData, updatedPokemon); - } - - /** - * Verify {@code params(Object... parameters)} parameters setting method. - */ - @Test - void testDmlArrayParams() { - executeTest("testDmlArrayParams", 50, "Shinx"); - } - - /** - * Verify {@code params(List)} parameters setting method. - */ - @Test - void testDmlListParams() { - executeTest("testDmlListParams", 51, "Luxio"); - } - - /** - * Verify {@code params(Map)} parameters setting method. - */ - @Test - void testDmlMapParams() { - executeTest("testDmlMapParams", 52, "Luxray"); - } - - /** - * Verify {@code addParam(Object parameter)} parameters setting method. - */ - @Test - void testDmlOrderParam() { - executeTest("testDmlOrderParam", 53, "Kricketot"); - } - - /** - * Verify {@code addParam(String name, Object parameter)} parameters setting method. - */ - @Test - void testDmlNamedParam() { - executeTest("testDmlNamedParam", 54, "Kricketune"); - } - - /** - * Verify {@code namedParam(Object parameters)} mapped parameters setting method. - */ - @Test - void testDmlMappedNamedParam() { - executeTest("testDmlMappedNamedParam", 55, "Phione"); - } - - /** - * Verify {@code indexedParam(Object parameters)} mapped parameters setting method. - */ - @Test - void testDmlMappedOrderParam() { - executeTest("testDmlMappedOrderParam", 56, "Chatot"); - } - -} diff --git a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/StatementGetIT.java b/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/StatementGetIT.java deleted file mode 100644 index b8d78eee4b3..00000000000 --- a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/StatementGetIT.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.lang.System.Logger.Level; - -import io.helidon.tests.integration.dbclient.app.LogData; -import io.helidon.tests.integration.dbclient.app.VerifyData; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; -import io.helidon.tests.integration.harness.TestClient; -import io.helidon.tests.integration.harness.TestServiceClient; - -import jakarta.json.JsonObject; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - -/** - * Test DML get statements. - */ -class StatementGetIT { - - private static final System.Logger LOGGER = System.getLogger(StatementGetIT.class.getName()); - - private final TestServiceClient testClient; - - StatementGetIT(int serverPort) { - this.testClient = TestClient.builder() - .port(serverPort) - .service("StatementGet") - .build(); - } - - private void executeTest(String testName, int fromId, int toId) { - LOGGER.log(Level.DEBUG, () -> String.format("Running %s.%s on client", getClass().getSimpleName(), testName)); - JsonObject data = testClient - .callServiceAndGetData( - testName, - QueryParams.builder() - .add(QueryParams.FROM_ID, String.valueOf(fromId)) - .add(QueryParams.TO_ID, String.valueOf(toId)) - .build()) - .asJsonObject(); - LogData.logJsonObject(Level.DEBUG, data); - int[] counter = {0}; - Pokemon.POKEMONS.keySet().forEach(id -> { - if (id > fromId && id < toId) { - Pokemon pokemon = Pokemon.POKEMONS.get(id); - VerifyData.verifyPokemon(data, pokemon); - counter[0]++; - } - }); - assertThat(counter[0], equalTo(1)); - } - - /** - * Verify {@code params(Object... parameters)} parameters setting method. - */ - @Test - void testGetArrayParams() { - executeTest("testGetArrayParams", 0, 2); - } - - /** - * Verify {@code params(List)} parameters setting method. - */ - @Test - void testGetListParams() { - executeTest("testGetListParams", 1, 3); - } - - /** - * Verify {@code params(Map)} parameters setting method. - */ - @Test - void testGetMapParams() { - executeTest("testGetMapParams", 2, 4); - } - - /** - * Verify {@code addParam(Object parameter)} parameters setting method. - */ - @Test - void testGetOrderParam() { - executeTest("testGetOrderParam", 3, 5); - - } - - /** - * Verify {@code addParam(String name, Object parameter)} parameters setting method. - */ - @Test - void testGetNamedParam() { - executeTest("testGetNamedParam", 4, 6); - } - - /** - * Verify {@code namedParam(Object parameters)} mapped parameters setting method. - */ - @Test - void testGetMappedNamedParam() { - executeTest("testGetMappedNamedParam", 5, 7); - } - - /** - * Verify {@code indexedParam(Object parameters)} mapped parameters setting method. - */ - @Test - void testGetMappedOrderParam() { - executeTest("testGetMappedOrderParam", 6, 8); - } - -} diff --git a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/StatementQueryIT.java b/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/StatementQueryIT.java deleted file mode 100644 index 229285d11df..00000000000 --- a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/StatementQueryIT.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.lang.System.Logger.Level; - -import io.helidon.tests.integration.dbclient.app.LogData; -import io.helidon.tests.integration.dbclient.app.VerifyData; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; -import io.helidon.tests.integration.harness.TestClient; -import io.helidon.tests.integration.harness.TestServiceClient; - -import jakarta.json.JsonArray; -import jakarta.json.JsonObject; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.lessThan; - -/** - * Test DML query statements. - */ -class StatementQueryIT { - - private static final System.Logger LOGGER = System.getLogger(StatementQueryIT.class.getName()); - - private final TestServiceClient testClient; - - StatementQueryIT(int serverPort) { - this.testClient = TestClient.builder() - .port(serverPort) - .service("StatementQuery") - .build(); - } - - private void executeTest(String testName, int fromId, int toId) { - LOGGER.log(Level.DEBUG, () -> String.format("Running %s.%s on client", getClass().getSimpleName(), testName)); - JsonArray data = testClient - .callServiceAndGetData( - testName, - QueryParams.builder() - .add(QueryParams.FROM_ID, String.valueOf(fromId)) - .add(QueryParams.TO_ID, String.valueOf(toId)) - .build()) - .asJsonArray(); - LogData.logJsonArray(Level.DEBUG, data); - assertThat(data.size(), equalTo(toId - fromId - 1)); - data.getValuesAs(JsonObject.class).forEach(dataPokemon -> { - int id = dataPokemon.getInt("id"); - Pokemon pokemon = Pokemon.POKEMONS.get(id); - assertThat(id, greaterThan(fromId)); - assertThat(id, lessThan(toId)); - VerifyData.verifyPokemon(dataPokemon, pokemon); - }); - } - - /** - * Verify {@code params(Object... parameters)} parameters setting method. - */ - @Test - void testQueryArrayParams() { - executeTest("testQueryArrayParams", 0, 7); - } - - /** - * Verify {@code params(List)} parameters setting method. - */ - @Test - void testQueryListParams() { - executeTest("testQueryListParams", 0, 7); - } - - /** - * Verify {@code params(Map)} parameters setting method. - */ - @Test - void testQueryMapParams() { - executeTest("testQueryMapParams", 0, 7); - } - - /** - * Verify {@code addParam(Object parameter)} parameters setting method. - */ - @Test - void testQueryOrderParam() { - executeTest("testQueryOrderParam", 0, 7); - } - - /** - * Verify {@code addParam(String name, Object parameter)} parameters setting method. - */ - @Test - void testQueryNamedParam() { - executeTest("testQueryNamedParam", 0, 7); - } - - /** - * Verify {@code namedParam(Object parameters)} mapped parameters setting method. - */ - @Test - void testQueryMappedNamedParam() { - executeTest("testQueryMappedNamedParam", 0, 7); - } - - /** - * Verify {@code indexedParam(Object parameters)} mapped parameters setting method. - */ - @Test - void testQueryMappedOrderParam() { - executeTest("testQueryMappedOrderParam", 0, 7); - } - -} diff --git a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/TransactionDeleteIT.java b/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/TransactionDeleteIT.java deleted file mode 100644 index be2d11b87a6..00000000000 --- a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/TransactionDeleteIT.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.lang.System.Logger.Level; - -import io.helidon.tests.integration.dbclient.app.LogData; -import io.helidon.tests.integration.dbclient.app.VerifyData; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; -import io.helidon.tests.integration.harness.JsonValues; -import io.helidon.tests.integration.harness.TestClient; -import io.helidon.tests.integration.harness.TestServiceClient; - -import jakarta.json.JsonObject; -import jakarta.json.JsonValue; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - -/** - * Test simple delete statements in transaction. - */ -class TransactionDeleteIT { - - private static final System.Logger LOGGER = System.getLogger(TransactionDeleteIT.class.getName()); - - private final TestServiceClient testClient; - - TransactionDeleteIT(int serverPort) { - this.testClient = TestClient.builder() - .port(serverPort) - .service("TransactionDelete") - .build(); - } - - private void executeTest(String testName, int id) { - LOGGER.log(Level.DEBUG, () -> String.format("Running %s.%s on client", getClass().getSimpleName(), testName)); - JsonValue data = testClient - .callServiceAndGetData( - testName, - QueryParams.single(QueryParams.ID, String.valueOf(id))); - Long count = JsonValues.asLong(data); - LOGGER.log(Level.DEBUG, () -> String.format("Rows deleted: %d", count)); - JsonObject pokemonData = VerifyData.getPokemon(testClient, id); - LogData.logJsonObject(Level.DEBUG, pokemonData); - assertThat(count, equalTo(1L)); - assertThat(pokemonData.isEmpty(), equalTo(true)); - } - - /** - * Verify {@code createNamedDelete(String, String)} API method with ordered parameters. - */ - @Test - void testCreateNamedDeleteStrStrOrderArgs() { - executeTest("testCreateNamedDeleteStrStrOrderArgs", 71); - } - - /** - * Verify {@code createNamedDelete(String)} API method with named parameters. - */ - @Test - void testCreateNamedDeleteStrNamedArgs() { - executeTest("testCreateNamedDeleteStrNamedArgs", 72); - } - - /** - * Verify {@code createNamedDelete(String)} API method with ordered parameters. - */ - @Test - void testCreateNamedDeleteStrOrderArgs() { - executeTest("testCreateNamedDeleteStrOrderArgs", 73); - } - - /** - * Verify {@code createDelete(String)} API method with named parameters. - */ - @Test - void testCreateDeleteNamedArgs() { - executeTest("testCreateDeleteNamedArgs", 74); - } - - /** - * Verify {@code createDelete(String)} API method with ordered parameters. - */ - @Test - void testCreateDeleteOrderArgs() { - executeTest("testCreateDeleteOrderArgs", 75); - } - - /** - * Verify {@code namedDelete(String)} API method with ordered parameters. - */ - @Test - void testNamedDeleteOrderArgs() { - executeTest("testNamedDeleteOrderArgs", 76); - } - - /** - * Verify {@code delete(String)} API method with ordered parameters. - */ - @Test - void testDeleteOrderArgs() { - executeTest("testDeleteOrderArgs", 77); - } - - // DML delete - - /** - * Verify {@code createNamedDmlStatement(String, String)} API method with delete with ordered parameters. - */ - @Test - void testCreateNamedDmlWithDeleteStrStrOrderArgs() { - executeTest("testCreateNamedDmlWithDeleteStrStrOrderArgs", 78); - } - - /** - * Verify {@code createNamedDmlStatement(String)} API method with delete with named parameters. - */ - @Test - void testCreateNamedDmlWithDeleteStrNamedArgs() { - executeTest("testCreateNamedDmlWithDeleteStrNamedArgs", 79); - } - - /** - * Verify {@code createNamedDmlStatement(String)} API method with delete with ordered parameters. - */ - @Test - void testCreateNamedDmlWithDeleteStrOrderArgs() { - executeTest("testCreateNamedDmlWithDeleteStrOrderArgs", 80); - } - - /** - * Verify {@code createDmlStatement(String)} API method with delete with named parameters. - */ - @Test - void testCreateDmlWithDeleteNamedArgs() { - executeTest("testCreateDmlWithDeleteNamedArgs", 81); - } - - /** - * Verify {@code createDmlStatement(String)} API method with delete with ordered parameters. - */ - @Test - void testCreateDmlWithDeleteOrderArgs() { - executeTest("testCreateDmlWithDeleteOrderArgs", 82); - } - - /** - * Verify {@code namedDml(String)} API method with delete with ordered parameters. - */ - @Test - void testNamedDmlWithDeleteOrderArgs() { - executeTest("testNamedDmlWithDeleteOrderArgs", 83); - } - - /** - * Verify {@code dml(String)} API method with delete with ordered parameters. - */ - @Test - void testDmlWithDeleteOrderArgs() { - executeTest("testDmlWithDeleteOrderArgs", 84); - } - -} diff --git a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/TransactionGetIT.java b/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/TransactionGetIT.java deleted file mode 100644 index bd989e0adea..00000000000 --- a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/TransactionGetIT.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.lang.System.Logger.Level; - -import io.helidon.tests.integration.dbclient.app.LogData; -import io.helidon.tests.integration.dbclient.app.VerifyData; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; -import io.helidon.tests.integration.harness.TestClient; -import io.helidon.tests.integration.harness.TestServiceClient; - -import jakarta.json.JsonObject; -import org.junit.jupiter.api.Test; - -/** - * Test simple get statements in transaction. - */ -class TransactionGetIT { - - private static final System.Logger LOGGER = System.getLogger(TransactionGetIT.class.getName()); - - private final TestServiceClient testClient; - - TransactionGetIT(int serverPort) { - this.testClient = TestClient.builder() - .port(serverPort) - .service("TransactionGet") - .build(); - } - - private void executeTest(String testName, Pokemon pokemon) { - LOGGER.log(Level.DEBUG, () -> String.format("Running %s.%s on client", getClass().getSimpleName(), testName)); - JsonObject data = testClient - .callServiceAndGetData( - testName, - QueryParams.single(QueryParams.NAME, pokemon.getName())) - .asJsonObject(); - LogData.logJsonObject(Level.DEBUG, data); - VerifyData.verifyPokemon(data, pokemon); - } - - /** - * Verify {@code createNamedGet(String, String)} API method with named - * parameters. - */ - @Test - void testCreateNamedGetStrStrNamedArgs() { - executeTest("testCreateNamedGetStrStrNamedArgs", Pokemon.POKEMONS.get(1)); - } - - /** - * Verify {@code createNamedGet(String)} API method with named parameters. - */ - @Test - void testCreateNamedGetStrNamedArgs() { - executeTest("testCreateNamedGetStrNamedArgs", Pokemon.POKEMONS.get(2)); - } - - /** - * Verify {@code createNamedGet(String)} API method with ordered parameters. - */ - @Test - void testCreateNamedGetStrOrderArgs() { - executeTest("testCreateNamedGetStrOrderArgs", Pokemon.POKEMONS.get(3)); - } - - /** - * Verify {@code createGet(String)} API method with named parameters. - */ - @Test - void testCreateGetNamedArgs() { - executeTest("testCreateGetNamedArgs", Pokemon.POKEMONS.get(4)); - } - - /** - * Verify {@code createGet(String)} API method with ordered parameters. - */ - @Test - void testCreateGetOrderArgs() { - executeTest("testCreateGetOrderArgs", Pokemon.POKEMONS.get(5)); - } - - /** - * Verify {@code namedGet(String)} API method with ordered parameters passed - * directly to the {@code query} method. - */ - @Test - void testNamedGetStrOrderArgs() { - executeTest("testNamedGetStrOrderArgs", Pokemon.POKEMONS.get(6)); - } - - /** - * Verify {@code get(String)} API method with ordered parameters passed - * directly to the {@code query} method. - */ - @Test - void testGetStrOrderArgs() { - executeTest("testGetStrOrderArgs", Pokemon.POKEMONS.get(7)); - } - -} diff --git a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/TransactionInsertIT.java b/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/TransactionInsertIT.java deleted file mode 100644 index 2da18e1bfd1..00000000000 --- a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/TransactionInsertIT.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.lang.System.Logger.Level; - -import io.helidon.tests.integration.dbclient.app.LogData; -import io.helidon.tests.integration.dbclient.app.VerifyData; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; -import io.helidon.tests.integration.harness.TestClient; -import io.helidon.tests.integration.harness.TestServiceClient; - -import jakarta.json.JsonObject; -import org.junit.jupiter.api.Test; - -/** - * Test simple insert statements in transaction. - */ -class TransactionInsertIT { - - private static final System.Logger LOGGER = System.getLogger(TransactionInsertIT.class.getName()); - - private final TestServiceClient testClient; - - TransactionInsertIT(int serverPort) { - this.testClient = TestClient.builder() - .port(serverPort) - .service("TransactionInsert") - .build(); - } - - private void executeTest(String testName, int id) { - LOGGER.log(Level.DEBUG, () -> String.format("Running %s.%s on client", getClass().getSimpleName(), testName)); - JsonObject data = testClient - .callServiceAndGetData( - testName, - QueryParams.single(QueryParams.ID, String.valueOf(id))) - .asJsonObject(); - LogData.logJsonObject(Level.DEBUG, data); - JsonObject pokemonData = VerifyData.getPokemon(testClient, id); - LogData.logJsonObject(Level.DEBUG, pokemonData); - VerifyData.verifyPokemon(pokemonData, data); - } - - /** - * Verify {@code createNamedInsert(String, String)} API method with named parameters. - */ - @Test - void testCreateNamedInsertStrStrNamedArgs() { - executeTest("testCreateNamedInsertStrStrNamedArgs", 85); - } - - /** - * Verify {@code createNamedInsert(String)} API method with named parameters. - */ - @Test - void testCreateNamedInsertStrNamedArgs() { - executeTest("testCreateNamedInsertStrNamedArgs", 86); - } - - /** - * Verify {@code createNamedInsert(String)} API method with ordered parameters. - */ - @Test - void testCreateNamedInsertStrOrderArgs() { - executeTest("testCreateNamedInsertStrOrderArgs", 87); - } - - /** - * Verify {@code createInsert(String)} API method with named parameters. - */ - @Test - void testCreateInsertNamedArgs() { - executeTest("testCreateInsertNamedArgs", 88); - } - - /** - * Verify {@code createInsert(String)} API method with ordered parameters. - */ - @Test - void testCreateInsertOrderArgs() { - executeTest("testCreateInsertOrderArgs", 89); - } - - /** - * Verify {@code namedInsert(String)} API method with ordered parameters passed directly to the {@code insert} method. - */ - @Test - void testNamedInsertOrderArgs() { - executeTest("testNamedInsertOrderArgs", 90); - } - - /** - * Verify {@code insert(String)} API method with ordered parameters passed directly to the {@code insert} method. - */ - @Test - void testInsertOrderArgs() { - executeTest("testInsertOrderArgs", 91); - } - - // DML update - - /** - * Verify {@code createNamedDmlStatement(String, String)} API method with insert with named parameters. - */ - @Test - void testCreateNamedDmlWithInsertStrStrNamedArgs() { - executeTest("testCreateNamedDmlWithInsertStrStrNamedArgs", 92); - } - - /** - * Verify {@code createNamedDmlStatement(String)} API method with insert with named parameters. - */ - @Test - void testCreateNamedDmlWithInsertStrNamedArgs() { - executeTest("testCreateNamedDmlWithInsertStrNamedArgs", 93); - } - - /** - * Verify {@code createNamedDmlStatement(String)} API method with insert with ordered parameters. - */ - @Test - void testCreateNamedDmlWithInsertStrOrderArgs() { - executeTest("testCreateNamedDmlWithInsertStrOrderArgs", 94); - } - - /** - * Verify {@code createDmlStatement(String)} API method with insert with named parameters. - */ - @Test - void testCreateDmlWithInsertNamedArgs() { - executeTest("testCreateDmlWithInsertNamedArgs", 95); - } - - /** - * Verify {@code createDmlStatement(String)} API method with insert with ordered parameters. - */ - @Test - void testCreateDmlWithInsertOrderArgs() { - executeTest("testCreateDmlWithInsertOrderArgs", 96); - } - - /** - * Verify {@code namedDml(String)} API method with insert with ordered parameters passed directly - * to the {@code insert} method. - */ - @Test - void testNamedDmlWithInsertOrderArgs() { - executeTest("testNamedDmlWithInsertOrderArgs", 97); - } - - /** - * Verify {@code dml(String)} API method with insert with ordered parameters passed directly - * to the {@code insert} method. - */ - @Test - void testDmlWithInsertOrderArgs() { - executeTest("testDmlWithInsertOrderArgs", 98); - } - -} diff --git a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/TransactionQueriesIT.java b/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/TransactionQueriesIT.java deleted file mode 100644 index 0e174779965..00000000000 --- a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/TransactionQueriesIT.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.lang.System.Logger.Level; - -import io.helidon.tests.integration.dbclient.app.LogData; -import io.helidon.tests.integration.dbclient.app.VerifyData; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; -import io.helidon.tests.integration.harness.TestClient; -import io.helidon.tests.integration.harness.TestServiceClient; - -import jakarta.json.JsonArray; -import org.hamcrest.Matchers; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Test simple query statements in transaction. - */ -class TransactionQueriesIT { - - /** - * Local logger instance. - */ - static final System.Logger LOGGER = System.getLogger(TransactionQueriesIT.class.getName()); - - private final TestServiceClient testClient; - - TransactionQueriesIT(int serverPort) { - this.testClient = TestClient.builder() - .port(serverPort) - .service("TransactionQueries") - .build(); - } - - private void executeTest(String testName, Pokemon pokemon) { - LOGGER.log(Level.DEBUG, () -> String.format("Running %s.%s on client", getClass().getSimpleName(), testName)); - JsonArray data = testClient - .callServiceAndGetData( - testName, - QueryParams.single(QueryParams.NAME, pokemon.getName())) - .asJsonArray(); - LogData.logJsonArray(Level.DEBUG, data); - assertThat(data.size(), Matchers.equalTo(1)); - VerifyData.verifyPokemon(data.getJsonObject(0), pokemon); - } - - /** - * Verify {@code createNamedQuery(String, String)} API method with ordered parameters. - */ - @Test - void testCreateNamedQueryStrStrOrderArgs() { - executeTest("testCreateNamedQueryStrStrOrderArgs", Pokemon.POKEMONS.get(1)); - } - - /** - * Verify {@code createNamedQuery(String)} API method with named parameters. - */ - @Test - void testCreateNamedQueryStrNamedArgs() { - executeTest("testCreateNamedQueryStrNamedArgs", Pokemon.POKEMONS.get(2)); - } - - /** - * Verify {@code createNamedQuery(String)} API method with ordered parameters. - */ - @Test - void testCreateNamedQueryStrOrderArgs() { - executeTest("testCreateNamedQueryStrOrderArgs", Pokemon.POKEMONS.get(3)); - } - - /** - * Verify {@code createQuery(String)} API method with named parameters. - */ - @Test - void testCreateQueryNamedArgs() { - executeTest("testCreateQueryNamedArgs", Pokemon.POKEMONS.get(4)); - } - - /** - * Verify {@code createQuery(String)} API method with ordered parameters. - */ - @Test - void testCreateQueryOrderArgs() { - executeTest("testCreateQueryOrderArgs", Pokemon.POKEMONS.get(5)); - } - - /** - * Verify {@code namedQuery(String)} API method with ordered parameters passed directly to the {@code namedQuery} method. - */ - @Test - void testNamedQueryOrderArgs() { - executeTest("testNamedQueryOrderArgs", Pokemon.POKEMONS.get(6)); - } - - /** - * Verify {@code query(String)} API method with ordered parameters passed directly to the {@code query} method. - */ - @Test - void testQueryOrderArgs() { - executeTest("testQueryOrderArgs", Pokemon.POKEMONS.get(7)); - } - -} diff --git a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/TransactionUpdateIT.java b/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/TransactionUpdateIT.java deleted file mode 100644 index 17f30ed15a6..00000000000 --- a/tests/integration/dbclient/app/src/test/java/io/helidon/tests/integration/dbclient/app/tests/TransactionUpdateIT.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.app.tests; - -import java.lang.System.Logger.Level; - -import io.helidon.tests.integration.dbclient.app.LogData; -import io.helidon.tests.integration.dbclient.app.VerifyData; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.app.tools.QueryParams; -import io.helidon.tests.integration.harness.JsonValues; -import io.helidon.tests.integration.harness.TestClient; -import io.helidon.tests.integration.harness.TestServiceClient; - -import jakarta.json.JsonObject; -import jakarta.json.JsonValue; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - -/** - * Test simple update statements in transaction. - */ -class TransactionUpdateIT { - - private static final System.Logger LOGGER = System.getLogger(TransactionUpdateIT.class.getName()); - - private final TestServiceClient testClient; - - TransactionUpdateIT(int serverPort) { - this.testClient = TestClient.builder() - .port(serverPort) - .service("TransactionUpdate") - .build(); - } - - private void executeTest(String testName, int id, String newName) { - LOGGER.log(Level.DEBUG, () -> String.format("Running %s.%s on client", getClass().getSimpleName(), testName));; - Pokemon pokemon = Pokemon.POKEMONS.get(id); - Pokemon updatedPokemon = new Pokemon(pokemon.getId(), newName, pokemon.getTypes()); - JsonValue data = testClient - .callServiceAndGetData( - testName, - QueryParams.builder() - .add(QueryParams.NAME, newName) - .add(QueryParams.ID, String.valueOf(id)) - .build()); - Long count = JsonValues.asLong(data); - JsonObject pokemonData = VerifyData.getPokemon(testClient, pokemon.getId()); - LogData.logJsonObject(Level.DEBUG, pokemonData); - assertThat(count, equalTo(1L)); - VerifyData.verifyPokemon(pokemonData, updatedPokemon); - } - - /** - * Verify {@code createNamedUpdate(String, String)} API method with ordered parameters. - */ - @Test - void testCreateNamedUpdateStrStrNamedArgs() { - executeTest("testCreateNamedUpdateStrStrNamedArgs", 57, "Ursaring"); - } - - /** - * Verify {@code createNamedUpdate(String)} API method with named parameters. - */ - @Test - void testCreateNamedUpdateStrNamedArgs() { - executeTest("testCreateNamedUpdateStrNamedArgs", 58, "Teddiursa"); - } - - /** - * Verify {@code createNamedUpdate(String, String)} API method with ordered parameters. - */ - @Test - void testCreateNamedUpdateStrOrderArgs() { - executeTest("testCreateNamedUpdateStrOrderArgs", 59, "Magcargo"); - } - - /** - * Verify {@code createUpdate(String)} API method with named parameters. - */ - @Test - void testCreateUpdateNamedArgs() { - executeTest("testCreateUpdateNamedArgs", 60, "Slugma"); - } - - - /** - * Verify {@code createUpdate(String)} API method with named parameters. - */ - @Test - void testCreateUpdateOrderArgs() { - executeTest("testCreateUpdateOrderArgs", 61, "Lombre"); - } - - /** - * Verify {@code namedUpdate(String, String)} API method with ordered parameters. - */ - @Test - void testNamedUpdateNamedArgs() { - executeTest("testNamedUpdateNamedArgs", 62, "Ludicolo"); - } - - /** - * Verify {@code update(String)} API method with named parameters. - */ - @Test - void testUpdateOrderArgs() { - executeTest("testUpdateOrderArgs", 63, "Lotad"); - } - - // DML update - - /** - * Verify {@code createNamedDmlStatement(String, String)} API method with update with named parameters. - */ - @Test - void testCreateNamedDmlWithUpdateStrStrNamedArgs() { - executeTest("testCreateNamedDmlWithUpdateStrStrNamedArgs", 64, "Xatu"); - } - - /** - * Verify {@code createNamedDmlStatement(String)} API method with update with named parameters. - */ - @Test - void testCreateNamedDmlWithUpdateStrNamedArgs() { - executeTest("testCreateNamedDmlWithUpdateStrNamedArgs", 65, "Natu"); - } - - /** - * Verify {@code createNamedDmlStatement(String)} API method with update with ordered parameters. - */ - @Test - void testCreateNamedDmlWithUpdateStrOrderArgs() { - executeTest("testCreateNamedDmlWithUpdateStrOrderArgs", 66, "Granbull"); - } - - /** - * Verify {@code createDmlStatement(String)} API method with update with named parameters. - */ - @Test - void testCreateDmlWithUpdateNamedArgs() { - executeTest("testCreateDmlWithUpdateNamedArgs", 67, "Snubbull"); - } - - /** - * Verify {@code createDmlStatement(String)} API method with update with ordered parameters. - */ - @Test - void testCreateDmlWithUpdateOrderArgs() { - executeTest("testCreateDmlWithUpdateOrderArgs", 68, "Raikou"); - } - - /** - * Verify {@code namedDml(String)} API method with update with ordered parameters passed directly - * to the {@code insert} method. - */ - @Test - void testNamedDmlWithUpdateOrderArgs() { - executeTest("testNamedDmlWithUpdateOrderArgs", 69, "Suicune"); - } - - /** - * Verify {@code dml(String)} API method with update with ordered parameters passed directly - * to the {@code insert} method. - */ - @Test - void testDmlWithUpdateOrderArgs() { - executeTest("testDmlWithUpdateOrderArgs", 70, "Entei"); - } -} diff --git a/tests/integration/dbclient/app/src/test/resources/logging.properties b/tests/integration/dbclient/app/src/test/resources/logging.properties deleted file mode 100644 index e1b27ef2055..00000000000 --- a/tests/integration/dbclient/app/src/test/resources/logging.properties +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2020, 2023 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. -# - -handlers=io.helidon.logging.jul.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=WARNING -io.helidon.level=INFO -io.helidon.config.level=INFO -io.helidon.webserver.http.level=WARNING -io.helidon.tests.integration.dbclient.app.level=INFO diff --git a/tests/integration/dbclient/common/pom.xml b/tests/integration/dbclient/common/pom.xml index a09d1f0565e..f59a76144e3 100644 --- a/tests/integration/dbclient/common/pom.xml +++ b/tests/integration/dbclient/common/pom.xml @@ -27,14 +27,9 @@ ../pom.xml helidon-tests-integration-dbclient-common - Helidon Tests Integration Database Client Common + Helidon Tests Integration DbClient Common - - io.helidon.tests.integration - helidon-tests-integration-harness - ${project.version} - io.helidon.config helidon-config @@ -59,10 +54,6 @@ org.eclipse.parsson parsson - - org.junit.jupiter - junit-jupiter-api - org.hamcrest hamcrest-all @@ -71,6 +62,10 @@ io.helidon.webserver helidon-webserver + + io.helidon.webserver + helidon-webserver-context + io.helidon.webserver.observe helidon-webserver-observe-metrics @@ -80,9 +75,8 @@ helidon-webserver-observe-health - io.micrometer - micrometer-core + io.helidon.webclient + helidon-webclient-http1 - diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/AbstractTestImpl.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/AbstractTestImpl.java new file mode 100644 index 00000000000..62d10013b36 --- /dev/null +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/AbstractTestImpl.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.common; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import io.helidon.config.Config; +import io.helidon.dbclient.DbClient; +import io.helidon.dbclient.DbRow; +import io.helidon.tests.integration.dbclient.common.model.Pokemon; +import io.helidon.tests.integration.dbclient.common.model.Pokemons; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; + +/** + * Base test implementation. + */ +public abstract class AbstractTestImpl { + + protected final DbClient db; + protected final Config config; + protected final Map statements; + + protected AbstractTestImpl(DbClient db, Config config) { + this.db = db; + this.config = config; + this.statements = config.get("db.statements").detach().asMap().get(); + } + + static void verifyPokemon(List rows, Pokemon expected) { + assertThat(rows, notNullValue()); + assertThat(rows, hasSize(1)); + DbRow row = rows.getFirst(); + int id = row.column(1).get(Integer.class); + String name = row.column(2).get(String.class); + assertThat(id, equalTo(expected.id())); + assertThat(name, expected.name().equals(name)); + } + + static void verifyPokemon(Stream rows, Pokemon pokemon) { + assertThat(rows, notNullValue()); + verifyPokemon(rows.toList(), pokemon); + } + + static void verifyPokemon(DbRow row, Pokemon expected) { + assertThat(row, is(not(nullValue()))); + int id = row.column(1).get(Integer.class); + String name = row.column(2).get(String.class); + assertThat(id, equalTo(expected.id())); + assertThat(name, expected.name().equals(name)); + } + + void verifyPokemonsIdRange(DbRow row, int idMin, int idMax) { + Map valid = range(idMin, idMax); + assertThat(row, is(not(nullValue()))); + int id = row.column(1).get(Integer.class); + String name = row.column(2).get(String.class); + assertThat(valid.containsKey(id), equalTo(true)); + assertThat(name, equalTo(valid.get(id).name())); + } + + static void verifyPokemon(Pokemon actual, Pokemon expected) { + assertThat(actual.id(), equalTo(expected.id())); + assertThat(actual.name(), equalTo(expected.name())); + } + + void verifyInsertPokemon(long result, Pokemon data) { + assertThat(result, equalTo(1L)); + DbRow row = db.execute() + .namedGet("select-pokemon-by-id", data.id()) + .orElse(null); + + assertThat(row, is(not(nullValue()))); + int id = row.column("id").get(Integer.class); + String name = row.column("name").get(String.class); + assertThat(id, equalTo(data.id())); + assertThat(name, data.name().equals(name)); + } + + void verifyUpdatePokemon(long result, Pokemon data) { + assertThat(result, equalTo(1L)); + DbRow row = db.execute() + .namedGet("select-pokemon-by-id", data.id()) + .orElse(null); + verifyPokemon(row, data); + } + + void verifyDeletePokemon(long result, Pokemon expected) { + assertThat(result, equalTo(1L)); + DbRow row = db.execute() + .namedGet("select-pokemon-by-id", expected.id()) + .orElse(null); + assertThat(row, is(nullValue())); + } + + Map range(int idMin, int idMax) { + return Pokemons.ALL.stream() + .filter(p -> p.id() > idMin && p.id() < idMax) + .collect(Collectors.toMap(Pokemon::id, Function.identity())); + } +} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/DBHelper.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/DBHelper.java new file mode 100644 index 00000000000..c031ed61727 --- /dev/null +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/DBHelper.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.common; + +import io.helidon.dbclient.DbClient; +import io.helidon.dbclient.DbClientException; +import io.helidon.dbclient.DbExecute; +import io.helidon.tests.integration.dbclient.common.model.Pokemons; +import io.helidon.tests.integration.dbclient.common.model.Types; + +/** + * Database helper. + */ +public class DBHelper { + + private DBHelper() { + // cannot be instantiated + } + + /** + * Create the schema. + * + * @param db db client + */ + public static void createSchema(DbClient db) { + try { + DbExecute exec = db.execute(); + exec.namedDml("create-types"); + exec.namedDml("create-pokemons"); + exec.namedDml("create-poketypes"); + } catch (DbClientException ex) { + ex.printStackTrace(System.err); + } + } + + /** + * Insert the default data. + * + * @param db db client + */ + public static void insertDataSet(DbClient db) { + try { + DbExecute exec = db.execute(); + Types.ALL.forEach(t -> exec.namedInsert("insert-type", t.id(), t.name())); + Pokemons.ALL.forEach(p -> exec.namedInsert("insert-pokemon", p.id(), p.name())); + Pokemons.ALL.forEach(p -> p.types().forEach(t -> exec.namedInsert("insert-poketype", p.id(), t.id()))); + } catch (DbClientException ex) { + ex.printStackTrace(System.err); + } + } +} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/DbClientITMain.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/DbClientITMain.java new file mode 100644 index 00000000000..11b8081049e --- /dev/null +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/DbClientITMain.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.common; + +import io.helidon.config.Config; +import io.helidon.dbclient.DbClient; +import io.helidon.dbclient.health.DbClientHealthCheck; +import io.helidon.logging.common.LogConfig; +import io.helidon.webserver.WebServer; +import io.helidon.webserver.WebServerConfig; +import io.helidon.webserver.observe.ObserveFeature; +import io.helidon.webserver.observe.health.HealthObserver; + +import static io.helidon.config.ConfigSources.classpath; + +/** + * The application main class. + */ +public class DbClientITMain { + + /** + * Cannot be instantiated. + */ + private DbClientITMain() { + } + + /** + * Application main entry point. + * + * @param args command line arguments. + */ + public static void main(String[] args) { + LogConfig.configureRuntime(); + Config config = Config.create( + classpath("db.yaml"), + classpath("db-common.yaml")); + Config.global(config); + + DbClient db = DbClient.create(config.get("db")); + if (config.get("db.create-schema").asBoolean().orElse(false)) { + DBHelper.createSchema(db); + } + if (config.get("db.insert-dataset").asBoolean().orElse(false)) { + DBHelper.insertDataSet(db); + } + + WebServer server = WebServer.builder() + .config(config.get("server")) + .update(r -> setup(db, config, r)) + .build() + .start(); + server.context().register(server); + + System.out.println("WEB server is up! http://localhost:" + server.port()); + } + + /** + * Set up the server. + * + * @param dbClient db client + * @param config config + * @param builder builder + */ + public static void setup(DbClient dbClient, Config config, WebServerConfig.Builder builder) { + builder.addFeature(observeFeature(dbClient, config, "healthNoDetails", "noDetails", false)); + builder.addFeature(observeFeature(dbClient, config, "healthDetails", "details", true)); + builder.routing(r -> r.register("/test", new TestService(dbClient, config))); + } + + private static ObserveFeature observeFeature(DbClient dbClient, + Config config, + String name, + String endpoint, + boolean details) { + return ObserveFeature.builder() + .observersDiscoverServices(false) + .endpoint(endpoint) + .name(name) + .addObserver(HealthObserver.builder() + .addCheck(DbClientHealthCheck.builder(dbClient) + .config(config.get("db.health-check")) + .name(name) + .build()) + .details(details) + .build()) + .build(); + } +} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/DbMapperProviderImpl.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/DbMapperProviderImpl.java new file mode 100644 index 00000000000..85b83ad06df --- /dev/null +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/DbMapperProviderImpl.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2019, 2024 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.tests.integration.dbclient.common; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import io.helidon.dbclient.DbMapper; +import io.helidon.dbclient.DbRow; +import io.helidon.dbclient.spi.DbMapperProvider; +import io.helidon.tests.integration.dbclient.common.model.Pokemon; +import io.helidon.tests.integration.dbclient.common.model.Range; + +/** + * Mapper provider used in integration tests. + */ +public final class DbMapperProviderImpl implements DbMapperProvider { + + private static final PokemonMapper POKEMON_MAPPER = new PokemonMapper(); + private static final RangeMapper RANGE_MAPPER = new RangeMapper(); + + @Override + @SuppressWarnings({"unchecked", "IfCanBeSwitch"}) + public Optional> mapper(Class type) { + if (type.equals(Range.class)) { + return Optional.of((DbMapper) RANGE_MAPPER); + } + if (type.equals(Pokemon.class)) { + return Optional.of((DbMapper) POKEMON_MAPPER); + } + return Optional.empty(); + } + + private static final class RangeMapper implements DbMapper { + + @Override + public Range read(DbRow row) { + throw new UnsupportedOperationException("Read operation is not implemented."); + } + + @Override + public Map toNamedParameters(Range value) { + return Map.of( + "idmin", value.idMin(), + "idmax", value.idMax()); + } + + @Override + public List toIndexedParameters(Range value) { + return List.of(value.idMin(), value.idMax()); + } + } + + private static final class PokemonMapper implements DbMapper { + + @Override + public Pokemon read(DbRow row) { + return new Pokemon(row.column("id").get(Integer.class), row.column("name").get(String.class)); + } + + @Override + public Map toNamedParameters(Pokemon pokemon) { + return Map.of( + "id", pokemon.id(), + "name", pokemon.name()); + } + + @Override + public List toIndexedParameters(Pokemon pokemon) { + return List.of(pokemon.name(), pokemon.id()); + } + } +} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/LocalTextContext.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/LocalTextContext.java new file mode 100644 index 00000000000..4405ed23d8e --- /dev/null +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/LocalTextContext.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.common; + +import java.util.Map; +import java.util.Optional; +import java.util.function.BiFunction; +import java.util.function.Supplier; + +import io.helidon.config.Config; +import io.helidon.config.ConfigSources; +import io.helidon.config.spi.ConfigNode; +import io.helidon.config.spi.ConfigSource; +import io.helidon.config.spi.LazyConfigSource; +import io.helidon.dbclient.DbClient; + +/** + * Tuple for local tests. + * + * @param delegate type + */ +public record LocalTextContext(DbClient db, Config config, Supplier delegateSupplier) { + + /** + * Create a new context. + * + * @param factory delegate factory + * @param overrides config overrides + * @param createSchema {@code true} to create the schema + * @param delegate type + * @return context + */ + public static LocalTextContext create(BiFunction factory, + Map> overrides, + boolean createSchema) { + Config config = Config.create( + new LazyMapConfigSourceImpl(overrides), + ConfigSources.classpath("db.yaml"), + ConfigSources.classpath("db-common.yaml")); + Config.global(config); + DbClient db = DbClient.create(config.get("db")); + T delegate = factory.apply(db, config); + if (createSchema) { + DBHelper.createSchema(db); + } + DBHelper.insertDataSet(db); + return new LocalTextContext<>(db, config, () -> delegate); + } + + /** + * Get the delegate. + * + * @return delegate + */ + public T delegate() { + return delegateSupplier.get(); + } + + private record LazyMapConfigSourceImpl(Map> map) implements ConfigSource, LazyConfigSource { + + @Override + public Optional node(String key) { + return Optional.ofNullable(map.get(key)) + .flatMap(v -> Optional.ofNullable(v.get())) + .map(Object::toString) + .map(ConfigNode.ValueNode::create); + } + } +} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/MapperProviderImpl.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/MapperProviderImpl.java new file mode 100644 index 00000000000..f2e58de9873 --- /dev/null +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/MapperProviderImpl.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.common; + +import io.helidon.common.mapper.Mapper; +import io.helidon.common.mapper.spi.MapperProvider; + +/** + * Mapper provider. + */ +public class MapperProviderImpl implements MapperProvider { + + @Override + public ProviderResponse mapper(Class sourceClass, Class targetClass, String qualifier) { + if (Number.class.isAssignableFrom(sourceClass)) { + Mapper mapper = numberMapper(targetClass); + if (mapper != null) { + return new ProviderResponse(Support.SUPPORTED, mapper); + } + } + return ProviderResponse.unsupported(); + } + + private Mapper numberMapper(Class targetClass) { + return switch (targetClass.getName()) { + case "byte", "java.lang.Byte" -> Number::byteValue; + case "int", "java.lang.Integer" -> Number::intValue; + case "long", "java.lang.Long" -> Number::longValue; + case "float", "java.lang.Float" -> Number::floatValue; + case "double", "java.lang.Double" -> Number::doubleValue; + default -> null; + }; + } +} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/MiscTest.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/MiscTest.java new file mode 100644 index 00000000000..564ec06fdc5 --- /dev/null +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/MiscTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.common; + + +/** + * Miscellaneous test. + */ +public interface MiscTest { + + /** + * Source data verification. + */ + void testFlowControl(); + + /** + * Check that statement interceptor was called before statement execution. + */ + void testStatementInterceptor(); + + /** + * Verify insertion of using indexed mapping. + */ + void testInsertWithOrderMapping(); + + /** + * Verify insertion of using named mapping. + */ + void testInsertWithNamedMapping(); + + /** + * Verify update of using indexed mapping. + */ + void testUpdateWithOrderMapping(); + + /** + * Verify update of using named mapping. + */ + void testUpdateWithNamedMapping(); + + /** + * Verify delete of using indexed mapping. + */ + void testDeleteWithOrderMapping(); + + /** + * Verify delete of using named mapping. + */ + void testDeleteWithNamedMapping(); + + /** + * Verify query of as a result using mapping. + */ + void testQueryWithMapping(); + + /** + * Verify get of as a result using mapping. + */ + void testGetWithMapping(); +} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/MiscTestImpl.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/MiscTestImpl.java new file mode 100644 index 00000000000..83b73e0bd68 --- /dev/null +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/MiscTestImpl.java @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.common; + +import java.util.List; +import java.util.stream.Stream; + +import io.helidon.config.Config; +import io.helidon.dbclient.DbClient; +import io.helidon.dbclient.DbClientService; +import io.helidon.dbclient.DbClientServiceContext; +import io.helidon.dbclient.DbRow; +import io.helidon.tests.integration.dbclient.common.model.Pokemon; +import io.helidon.tests.integration.dbclient.common.model.Pokemons; +import io.helidon.tests.integration.dbclient.common.model.Type; +import io.helidon.tests.integration.dbclient.common.model.Types; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.nullValue; + +/** + * Actual implementation of {@link MiscTest}. + */ +public final class MiscTestImpl extends AbstractTestImpl implements MiscTest { + + /** + * Create a new instance. + * + * @param db db client + * @param config config + */ + public MiscTestImpl(DbClient db, Config config) { + super(db, config); + } + + @Override + public void testFlowControl() { + List actual = db.execute().namedQuery("select-types") + .map(row -> new Type(row.column(1).get(Integer.class), row.column(2).get(String.class))) + .toList(); + assertThat(actual.size(), equalTo(18)); + assertThat(actual, is(Types.ALL)); + } + + @Override + public void testStatementInterceptor() { + TestDbClientService interceptor = new TestDbClientService(); + try (DbClient db = DbClient.builder(config.get("db")).addService(interceptor).build()) { + db.execute() + .createNamedQuery("select-pokemon-named-arg") + .addParam("name", Pokemons.MEOWTH.name()) + .execute(); + assertThat(interceptor.called(), equalTo(true)); + } + } + + @Override + public void testInsertWithOrderMapping() { + Pokemon pokemon = new Pokemon(600, "Articuno", Types.FLYING, Types.ICE); + long result = db.execute() + .createNamedInsert("insert-pokemon-order-arg-rev") + .indexedParam(pokemon) + .execute(); + verifyInsertPokemon(result, pokemon); + } + + @Override + public void testInsertWithNamedMapping() { + Pokemon pokemon = new Pokemon(601, "Zapdos", Types.FLYING, Types.ELECTRIC); + long result = db.execute() + .createNamedInsert("insert-pokemon-named-arg") + .namedParam(pokemon) + .execute(); + verifyInsertPokemon(result, pokemon); + } + + @Override + public void testUpdateWithOrderMapping() { + Pokemon pokemon = new Pokemon(100, "UpdatedMasquerain", Types.FLYING, Types.ICE); + long result = db.execute() + .createNamedUpdate("update-pokemon-order-arg") + .indexedParam(pokemon) + .execute(); + verifyUpdatePokemon(result, pokemon); + } + + @Override + public void testUpdateWithNamedMapping() { + Pokemon pokemon = new Pokemon(99, "UpdatedMoltres", Types.FLYING, Types.ELECTRIC); + long result = db.execute() + .createNamedUpdate("update-pokemon-named-arg") + .namedParam(pokemon) + .execute(); + verifyUpdatePokemon(result, pokemon); + } + + @Override + public void testDeleteWithOrderMapping() { + Pokemon pokemon = Pokemons.MAKUHITA; + long result = db.execute() + .createNamedDelete("delete-pokemon-full-order-arg") + .indexedParam(pokemon) + .execute(); + + assertThat(result, equalTo(1L)); + DbRow row = db.execute() + .namedGet("select-pokemon-by-id", pokemon.id()) + .orElse(null); + assertThat(row, is(nullValue())); + } + + @Override + public void testDeleteWithNamedMapping() { + Pokemon pokemon = Pokemons.HARIYAMA; + + long result = db.execute() + .createNamedDelete("delete-pokemon-full-named-arg") + .namedParam(pokemon) + .execute(); + + assertThat(result, equalTo(1L)); + DbRow row = db.execute() + .namedGet("select-pokemon-by-id", pokemon.id()) + .orElse(null); + assertThat(row, is(nullValue())); + } + + @Override + public void testQueryWithMapping() { + Pokemon orig = Pokemons.RAICHU; + Stream rows = db.execute() + .createNamedQuery("select-pokemon-named-arg") + .addParam("name", orig.name()) + .execute(); + + Pokemon actual = rows.map(it -> it.as(Pokemon.class)).findFirst().orElseThrow(); + verifyPokemon(actual, orig); + } + + @Override + public void testGetWithMapping() { + Pokemon orig = Pokemons.MACHOP; + DbRow row = db.execute() + .createNamedGet("select-pokemon-named-arg") + .addParam("name", orig.name()) + .execute() + .orElse(null); + + assertThat(row, is(not(nullValue()))); + Pokemon actual = row.as(Pokemon.class); + verifyPokemon(actual, orig); + } + + private static final class TestDbClientService implements DbClientService { + + private boolean called; + + private TestDbClientService() { + this.called = false; + } + + @Override + public DbClientServiceContext statement(DbClientServiceContext context) { + this.called = true; + return context; + } + + private boolean called() { + return called; + } + + } +} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/ObservabilityTest.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/ObservabilityTest.java new file mode 100644 index 00000000000..b57cced29ee --- /dev/null +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/ObservabilityTest.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.common; + +/** + * Observability test. + */ +public interface ObservabilityTest { + + /** + * Read and check Database Client health status from Helidon Web Server. + */ + void testHttpHealthNoDetails(); + + /** + * Read and check Database Client health status from Helidon Web Server. + */ + void testHttpHealthDetails(); + + /** + * Read and check Database Client metrics from Helidon Web Server. + */ + void testHttpMetrics(); + + /** + * Verify health check implementation with default settings. + */ + void testHealthCheck(); + + /** + * Verify health check implementation with builder and custom name. + */ + void testHealthCheckWithName(); + + /** + * Verify health check implementation using custom DML named statement. + */ + void testHealthCheckWithCustomNamedDML(); + + /** + * Verify health check implementation using custom DML statement. + */ + void testHealthCheckWithCustomDML(); + + /** + * Verify health check implementation using custom query named statement. + */ + void testHealthCheckWithCustomNamedQuery(); + + /** + * Verify health check implementation using custom query statement. + */ + void testHealthCheckWithCustomQuery(); + +} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/ObservabilityTestImpl.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/ObservabilityTestImpl.java new file mode 100644 index 00000000000..ee8f4990caf --- /dev/null +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/ObservabilityTestImpl.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.common; + +import java.util.List; +import java.util.function.Supplier; + +import io.helidon.common.LazyValue; +import io.helidon.common.media.type.MediaTypes; +import io.helidon.config.Config; +import io.helidon.dbclient.DbClient; +import io.helidon.dbclient.DbRow; +import io.helidon.dbclient.health.DbClientHealthCheck; +import io.helidon.health.HealthCheck; +import io.helidon.health.HealthCheckResponse; +import io.helidon.http.Status; +import io.helidon.tests.integration.dbclient.common.model.Pokemon; +import io.helidon.tests.integration.dbclient.common.model.Types; +import io.helidon.webclient.api.ClientResponseTyped; +import io.helidon.webclient.http1.Http1Client; +import io.helidon.webclient.http1.Http1ClientRequest; + +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.json.JsonValue; +import org.hamcrest.CoreMatchers; + +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; + +/** + * Actual implementation of {@link ObservabilityTest}. + */ +public final class ObservabilityTestImpl extends AbstractTestImpl implements ObservabilityTest { + + private final LazyValue client; + + /** + * Create a new instance. + * + * @param db db client + * @param config config + * @param clientSupplier client supplier + */ + public ObservabilityTestImpl(DbClient db, Config config, Supplier clientSupplier) { + super(db, config); + client = LazyValue.create(clientSupplier); + } + + @Override + public void testHttpHealthNoDetails() { + // Call select-pokemons to warm up server + List ignored = db.execute().namedQuery("select-pokemons").toList(); + + ClientResponseTyped response = get("/noDetails/health").request(String.class); + assertThat(response.status(), equalTo(Status.NO_CONTENT_204)); + } + + @Override + public void testHttpHealthDetails() { + // Call select-pokemons to warm up server + List ignored = db.execute().namedQuery("select-pokemons").toList(); + + // Read and process health check response + ClientResponseTyped response = get("/details/health").request(JsonObject.class); + assertThat(response.status(), equalTo(Status.OK_200)); + + JsonArray checks = response.entity().asJsonObject().getJsonArray("checks"); + assertThat(checks.size(), greaterThan(0)); + for (JsonValue check : checks) { + String status = check.asJsonObject().getString("status"); + assertThat(status, equalTo("UP")); + } + } + + @Override + public void testHttpMetrics() { + // Read and process metrics response + JsonObject application = get("/observe/metrics/application") + .accept(MediaTypes.APPLICATION_JSON) + .requestEntity(JsonObject.class); + + int origSelectCount = application.getInt("db.counter.select-pokemons", 0); + int origInsertCount = application.getInt("db.counter.insert-pokemon", 0); + JsonObject insertTimer = application.getJsonObject("db.timer.insert-pokemon"); + int origInsertTimerCount = insertTimer == null ? 0 : insertTimer.getInt("count", 0); + + // Call select-pokemons + List ignored = db.execute().namedQuery("select-pokemons").toList(); + + // Call insert-pokemon + Pokemon pokemon = new Pokemon(401, "Lickitung", Types.NORMAL); + db.execute().namedInsert("insert-pokemon", pokemon.id(), pokemon.name()); + + // Read and process metrics response + application = get("/observe/metrics/application") + .accept(MediaTypes.APPLICATION_JSON) + .requestEntity(JsonObject.class); + + int actualSelectCount = application.getInt("db.counter.select-pokemons", 0); + assertThat(actualSelectCount, is(origSelectCount + 1)); + + int actualInsertCount = application.getInt("db.counter.insert-pokemon", 0); + assertThat(actualInsertCount, equalTo(origInsertCount + 1)); + assertThat(application.containsKey("db.timer.insert-pokemon"), equalTo(true)); + + insertTimer = application.getJsonObject("db.timer.insert-pokemon"); + assertThat(insertTimer, is(not(nullValue()))); + assertThat(insertTimer.containsKey("count"), equalTo(true)); + assertThat(insertTimer.containsKey("mean"), equalTo(true)); + assertThat(insertTimer.containsKey("max"), equalTo(true)); + + int actualInsertTimerCount = insertTimer.getInt("count"); + assertThat(actualInsertTimerCount, equalTo(origInsertTimerCount + 1)); + } + + @Override + public void testHealthCheck() { + HealthCheck check = DbClientHealthCheck.create(db, config.get("db.health-check")); + HealthCheckResponse response = check.call(); + HealthCheckResponse.Status state = response.status(); + assertThat("Health check failed, response: " + response.details(), state, equalTo(HealthCheckResponse.Status.UP)); + } + + @Override + public void testHealthCheckWithName() { + String hcName = "TestHC"; + HealthCheck check = DbClientHealthCheck.builder(db).config(config.get("db.health-check")).name(hcName).build(); + HealthCheckResponse response = check.call(); + String name = check.name(); + HealthCheckResponse.Status state = response.status(); + assertThat(name, equalTo(hcName)); + assertThat(state, equalTo(HealthCheckResponse.Status.UP)); + } + + @Override + public void testHealthCheckWithCustomNamedDML() { + HealthCheck check = DbClientHealthCheck.builder(db).dml().statementName("ping-dml").build(); + HealthCheckResponse response = check.call(); + HealthCheckResponse.Status state = response.status(); + assertThat("Health check failed, response: " + response.details(), state, equalTo(HealthCheckResponse.Status.UP)); + } + + @Override + public void testHealthCheckWithCustomDML() { + Config cfgStatement = config.get("db.statements.ping-dml"); + assertThat("Missing ping-dml statement in database configuration!", cfgStatement.exists(), equalTo(true)); + String statement = cfgStatement.asString().get(); + assertThat("Missing ping-dml statement String in database configuration!", statement, CoreMatchers.is(notNullValue())); + HealthCheck check = DbClientHealthCheck.builder(db).dml().statement(statement).build(); + HealthCheckResponse response = check.call(); + HealthCheckResponse.Status state = response.status(); + assertThat("Health check failed, response: " + response.details(), state, equalTo(HealthCheckResponse.Status.UP)); + } + + @Override + public void testHealthCheckWithCustomNamedQuery() { + HealthCheck check = DbClientHealthCheck.builder(db).query().statementName("ping").build(); + HealthCheckResponse response = check.call(); + HealthCheckResponse.Status state = response.status(); + assertThat("Health check failed, response: " + response.details(), state, equalTo(HealthCheckResponse.Status.UP)); + } + + @Override + public void testHealthCheckWithCustomQuery() { + Config cfgStatement = config.get("db.statements.ping"); + assertThat("Missing ping-query statement in database configuration!", cfgStatement.exists(), equalTo(true)); + String statement = cfgStatement.asString().get(); + assertThat("Missing ping-query statement String in database configuration!", statement, CoreMatchers.is(notNullValue())); + HealthCheck check = DbClientHealthCheck.builder(db).query().statement(statement).build(); + HealthCheckResponse response = check.call(); + HealthCheckResponse.Status state = response.status(); + assertThat("Health check failed, response: " + response.details(), state, equalTo(HealthCheckResponse.Status.UP)); + } + + private Http1ClientRequest get(String path) { + return client.get().get(path); + } +} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/RemoteTest.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/RemoteTest.java new file mode 100644 index 00000000000..4898ce80dd1 --- /dev/null +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/RemoteTest.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.common; + +import java.util.NoSuchElementException; + +import io.helidon.http.Status; +import io.helidon.webclient.http1.Http1Client; +import io.helidon.webclient.http1.Http1ClientResponse; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +/** + * Base class for remote tests. + */ +public abstract class RemoteTest { + private final Http1Client client; + + /** + * Create a new instance. + * + * @param path base path + * @param port port + */ + protected RemoteTest(String path, int port) { + client = Http1Client.builder() + .baseUri("http://localhost:" + port + path) + .build(); + } + + /** + * Invoke a GET request against {@code /{path}/{testName}} and assert a {@code 200} response status. + */ + protected void remoteTest() { + String testName = findTestName(); + Http1ClientResponse response = client.get(testName).request(); + assertThat(response.status(), is(Status.OK_200)); + } + + private String findTestName() { + return StackWalker.getInstance().walk(s -> + s.dropWhile(f -> f.getClassName().equals(RemoteTest.class.getName())) + .findFirst() + .map(StackWalker.StackFrame::getMethodName) + .orElseThrow(() -> new NoSuchElementException("Unable to find caller method name"))); + } +} diff --git a/tests/integration/dbclient/h2/src/main/java/module-info.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/SimpleTest.java similarity index 53% rename from tests/integration/dbclient/h2/src/main/java/module-info.java rename to tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/SimpleTest.java index bec50ffe7ec..6ffacc168bb 100644 --- a/tests/integration/dbclient/h2/src/main/java/module-info.java +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/SimpleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2024 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. @@ -13,20 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package io.helidon.tests.integration.dbclient.common; /** - * Helidon Database Client Integration Tests with H2 Database. + * Simple test. */ -module io.helidon.tests.integration.dbclient.h2 { - - requires java.sql; - requires com.h2database; - - requires io.helidon.config; - requires io.helidon.dbclient; - requires io.helidon.tests.integration.dbclient.common; - - provides io.helidon.tests.integration.dbclient.common.spi.SetupProvider - with io.helidon.tests.integration.dbclient.jdbc.H2SetupProvider; - -} \ No newline at end of file +public interface SimpleTest extends SimpleTests.DeleteTest, + SimpleTests.DmlTest, + SimpleTests.GetTest, + SimpleTests.InsertTest, + SimpleTests.QueriesTest, + SimpleTests.UpdateTest { +} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/SimpleTestImpl.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/SimpleTestImpl.java new file mode 100644 index 00000000000..54eacadc05e --- /dev/null +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/SimpleTestImpl.java @@ -0,0 +1,614 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.common; + +import java.util.stream.Stream; + +import io.helidon.config.Config; +import io.helidon.dbclient.DbClient; +import io.helidon.dbclient.DbRow; +import io.helidon.tests.integration.dbclient.common.model.Pokemon; +import io.helidon.tests.integration.dbclient.common.model.Pokemons; +import io.helidon.tests.integration.dbclient.common.model.Types; + +/** + * Actual implementation of {@link SimpleTests}. + */ +public final class SimpleTestImpl extends AbstractTestImpl implements SimpleTest { + + /** + * Create a new instance. + * + * @param db db client + * @param config config + */ + public SimpleTestImpl(DbClient db, Config config) { + super(db, config); + } + + @Override + public void testCreateNamedDeleteStrStrOrderArgs() { + Pokemon orig = Pokemons.RAYQUAZA; + String stmt = statements.get("delete-pokemon-order-arg"); + long result = db.execute() + .createNamedDelete("delete-rayquaza", stmt) + .addParam(orig.id()).execute(); + verifyDeletePokemon(result, orig); + } + + @Override + public void testCreateNamedDeleteStrNamedArgs() { + Pokemon orig = Pokemons.LUGIA; + long result = db.execute() + .createNamedDelete("delete-pokemon-named-arg") + .addParam("id", orig.id()).execute(); + verifyDeletePokemon(result, orig); + } + + @Override + public void testCreateNamedDeleteStrOrderArgs() { + Pokemon orig = Pokemons.HOOH; + long result = db.execute() + .createNamedDelete("delete-pokemon-order-arg") + .addParam(orig.id()).execute(); + verifyDeletePokemon(result, orig); + } + + @Override + public void testCreateDeleteNamedArgs() { + Pokemon orig = Pokemons.RAIKOU; + String stmt = statements.get("delete-pokemon-named-arg"); + long result = db.execute() + .createDelete(stmt) + .addParam("id", orig.id()).execute(); + verifyDeletePokemon(result, orig); + } + + @Override + public void testCreateDeleteOrderArgs() { + Pokemon orig = Pokemons.GIRATINA; + String stmt = statements.get("delete-pokemon-order-arg"); + long result = db.execute() + .createDelete(stmt) + .addParam(orig.id()).execute(); + verifyDeletePokemon(result, orig); + } + + @Override + public void testNamedDeleteOrderArgs() { + Pokemon orig = Pokemons.REGIROCK; + long result = db.execute() + .namedDelete("delete-pokemon-order-arg", orig.id()); + verifyDeletePokemon(result, orig); + } + + @Override + public void testDeleteOrderArgs() { + Pokemon orig = Pokemons.KYOGRE; + String stmt = statements.get("delete-pokemon-order-arg"); + long result = db.execute() + .delete(stmt, orig.id()); + verifyDeletePokemon(result, orig); + } + + @Override + public void testCreateNamedDmlWithInsertStrStrNamedArgs() { + Pokemon pokemon = new Pokemon(200, "Torchic", Types.FIRE); + String stmt = statements.get("insert-pokemon-named-arg"); + long result = db.execute() + .createNamedDmlStatement("insert-torchic", stmt) + .addParam("id", pokemon.id()).addParam("name", pokemon.name()) + .execute(); + verifyInsertPokemon(result, pokemon); + } + + @Override + public void testCreateNamedDmlWithInsertStrNamedArgs() { + Pokemon pokemon = new Pokemon(201, "Combusken", Types.FLYING, Types.FIRE); + long result = db.execute() + .createNamedDmlStatement("insert-pokemon-named-arg") + .addParam("id", pokemon.id()).addParam("name", pokemon.name()) + .execute(); + verifyInsertPokemon(result, pokemon); + } + + @Override + public void testCreateNamedDmlWithInsertStrOrderArgs() { + Pokemon pokemon = new Pokemon(202, "Treecko", Types.GRASS); + long result = db.execute() + .createNamedDmlStatement("insert-pokemon-order-arg") + .addParam(pokemon.id()).addParam(pokemon.name()) + .execute(); + verifyInsertPokemon(result, pokemon); + } + + @Override + public void testCreateDmlWithInsertNamedArgs() { + Pokemon pokemon = new Pokemon(203, "Grovyle", Types.GRASS); + String stmt = statements.get("insert-pokemon-named-arg"); + long result = db.execute() + .createDmlStatement(stmt) + .addParam("id", pokemon.id()).addParam("name", pokemon.name()) + .execute(); + verifyInsertPokemon(result, pokemon); + } + + @Override + public void testCreateDmlWithInsertOrderArgs() { + Pokemon pokemon = new Pokemon(204, "Sceptile", Types.GRASS); + String stmt = statements.get("insert-pokemon-order-arg"); + long result = db.execute() + .createDmlStatement(stmt) + .addParam(pokemon.id()).addParam(pokemon.name()) + .execute(); + verifyInsertPokemon(result, pokemon); + } + + @Override + public void testNamedDmlWithInsertOrderArgs() { + Pokemon pokemon = new Pokemon(205, "Snover", Types.GRASS, Types.ICE); + long result = db.execute() + .namedDml("insert-pokemon-order-arg", pokemon.id(), pokemon.name()); + verifyInsertPokemon(result, pokemon); + } + + @Override + public void testDmlWithInsertOrderArgs() { + Pokemon pokemon = new Pokemon(206, "Abomasnow", Types.GRASS, Types.ICE); + String stmt = statements.get("insert-pokemon-order-arg"); + long result = db.execute() + .dml(stmt, pokemon.id(), pokemon.name()); + verifyInsertPokemon(result, pokemon); + } + + @Override + public void testCreateNamedDmlWithUpdateStrStrNamedArgs() { + Pokemon orig = Pokemons.PIPLUP; + Pokemon updated = new Pokemon(orig.id(), "UpdatedPiplup", orig.types()); + String stmt = statements.get("update-pokemon-named-arg"); + long result = db.execute() + .createNamedDmlStatement("update-piplup", stmt) + .addParam("name", updated.name()).addParam("id", updated.id()) + .execute(); + verifyUpdatePokemon(result, updated); + } + + @Override + public void testCreateNamedDmlWithUpdateStrNamedArgs() { + Pokemon orig = Pokemons.PRINPLUP; + Pokemon updated = new Pokemon(orig.id(), "UpdatedPrinplup", orig.types()); + long result = db.execute() + .createNamedDmlStatement("update-pokemon-named-arg") + .addParam("name", updated.name()).addParam("id", updated.id()) + .execute(); + verifyUpdatePokemon(result, updated); + } + + @Override + public void testCreateNamedDmlWithUpdateStrOrderArgs() { + Pokemon orig = Pokemons.EMPOLEON; + Pokemon updated = new Pokemon(orig.id(), "UpdatedEmpoleon", orig.types()); + long result = db.execute() + .createNamedDmlStatement("update-pokemon-order-arg") + .addParam(updated.name()).addParam(updated.id()) + .execute(); + verifyUpdatePokemon(result, updated); + } + + @Override + public void testCreateDmlWithUpdateNamedArgs() { + Pokemon orig = Pokemons.STARYU; + Pokemon updated = new Pokemon(orig.id(), "UpdatedStaryu", orig.types()); + String stmt = statements.get("update-pokemon-named-arg"); + long result = db.execute() + .createDmlStatement(stmt) + .addParam("name", updated.name()).addParam("id", updated.id()) + .execute(); + verifyUpdatePokemon(result, updated); + } + + @Override + public void testCreateDmlWithUpdateOrderArgs() { + Pokemon orig = Pokemons.STARMIE; + Pokemon updated = new Pokemon(orig.id(), "UpdatedStarmie", orig.types()); + String stmt = statements.get("update-pokemon-order-arg"); + long result = db.execute() + .createDmlStatement(stmt) + .addParam(updated.name()).addParam(updated.id()) + .execute(); + verifyUpdatePokemon(result, updated); + } + + @Override + public void testNamedDmlWithUpdateOrderArgs() { + Pokemon orig = Pokemons.HORSEA; + Pokemon updated = new Pokemon(orig.id(), "UpdatedHorsea", orig.types()); + long result = db.execute() + .namedDml("update-pokemon-order-arg", updated.name(), updated.id()); + verifyUpdatePokemon(result, updated); + } + + @Override + public void testDmlWithUpdateOrderArgs() { + Pokemon orig = Pokemons.SEADRA; + Pokemon updated = new Pokemon(orig.id(), "UpdatedSeadra", orig.types()); + String stmt = statements.get("update-pokemon-order-arg"); + long result = db.execute() + .dml(stmt, updated.name(), updated.id()); + verifyUpdatePokemon(result, updated); + } + + @Override + public void testCreateNamedDmlWithDeleteStrStrOrderArgs() { + Pokemon pokemon = Pokemons.MUDKIP; + String stmt = statements.get("delete-pokemon-order-arg"); + long result = db.execute() + .createNamedDmlStatement("delete-mudkip", stmt) + .addParam(pokemon.id()) + .execute(); + verifyDeletePokemon(result, pokemon); + } + + @Override + public void testCreateNamedDmlWithDeleteStrNamedArgs() { + Pokemon pokemon = Pokemons.MARSHTOMP; + long result = db.execute() + .createNamedDmlStatement("delete-pokemon-named-arg") + .addParam("id", pokemon.id()) + .execute(); + verifyDeletePokemon(result, pokemon); + } + + @Override + public void testCreateNamedDmlWithDeleteStrOrderArgs() { + Pokemon pokemon = Pokemons.SWAMPERT; + long result = db.execute() + .createNamedDmlStatement("delete-pokemon-order-arg") + .addParam(pokemon.id()) + .execute(); + verifyDeletePokemon(result, pokemon); + } + + @Override + public void testCreateDmlWithDeleteNamedArgs() { + Pokemon pokemon = Pokemons.MUK; + String stmt = statements.get("delete-pokemon-named-arg"); + long result = db.execute() + .createDmlStatement(stmt) + .addParam("id", pokemon.id()) + .execute(); + verifyDeletePokemon(result, pokemon); + } + + @Override + public void testCreateDmlWithDeleteOrderArgs() { + Pokemon pokemon = Pokemons.GRIMER; + String stmt = statements.get("delete-pokemon-order-arg"); + long result = db.execute() + .createDmlStatement(stmt) + .addParam(pokemon.id()) + .execute(); + verifyDeletePokemon(result, pokemon); + } + + @Override + public void testNamedDmlWithDeleteOrderArgs() { + Pokemon pokemon = Pokemons.CUBCHOO; + long result = db.execute().namedDml("delete-pokemon-order-arg", pokemon.id()); + verifyDeletePokemon(result, pokemon); + } + + @Override + public void testDmlWithDeleteOrderArgs() { + Pokemon pokemon = Pokemons.BEARTIC; + String stmt = statements.get("delete-pokemon-order-arg"); + long result = db.execute().dml(stmt, pokemon.id()); + verifyDeletePokemon(result, pokemon); + } + + @Override + public void testCreateNamedGetStrStrNamedArgs() { + Pokemon expected = Pokemons.PIKACHU; + String stmt = statements.get("select-pokemon-named-arg"); + DbRow row = db.execute() + .createNamedGet("select-pikachu", stmt) + .addParam("name", expected.name()) + .execute() + .orElse(null); + verifyPokemon(row, expected); + } + + @Override + public void testCreateNamedGetStrNamedArgs() { + Pokemon expected = Pokemons.RAICHU; + DbRow row = db.execute() + .createNamedGet("select-pokemon-named-arg") + .addParam("name", expected.name()) + .execute() + .orElse(null); + verifyPokemon(row, expected); + } + + @Override + public void testCreateNamedGetStrOrderArgs() { + Pokemon expected = Pokemons.MACHOP; + DbRow row = db.execute() + .createNamedGet("select-pokemon-order-arg") + .addParam(expected.name()) + .execute() + .orElse(null); + verifyPokemon(row, expected); + } + + @Override + public void testCreateGetNamedArgs() { + Pokemon expected = Pokemons.SNORLAX; + String stmt = statements.get("select-pokemon-named-arg"); + DbRow row = db.execute() + .createGet(stmt) + .addParam("name", expected.name()) + .execute() + .orElse(null); + verifyPokemon(row, expected); + } + + @Override + public void testCreateGetOrderArgs() { + Pokemon expected = Pokemons.CHARIZARD; + String stmt = statements.get("select-pokemon-order-arg"); + DbRow row = db.execute() + .createGet(stmt) + .addParam(expected.name()) + .execute() + .orElse(null); + verifyPokemon(row, expected); + } + + @Override + public void testNamedGetStrOrderArgs() { + Pokemon expected = Pokemons.MEOWTH; + DbRow row = db.execute() + .namedGet("select-pokemon-order-arg", expected.name()) + .orElse(null); + verifyPokemon(row, expected); + } + + @Override + public void testGetStrOrderArgs() { + Pokemon expected = Pokemons.GYARADOS; + String stmt = statements.get("select-pokemon-order-arg"); + DbRow row = db.execute() + .get(stmt, expected.name()) + .orElse(null); + verifyPokemon(row, expected); + } + + @Override + public void testCreateNamedInsertStrStrNamedArgs() { + Pokemon pokemon = new Pokemon(300, "Bulbasaur", Types.POISON, Types.GRASS); + String stmt = statements.get("insert-pokemon-named-arg"); + long result = db.execute() + .createNamedInsert("insert-bulbasaur", stmt) + .addParam("id", pokemon.id()).addParam("name", pokemon.name()) + .execute(); + verifyInsertPokemon(result, pokemon); + } + + @Override + public void testCreateNamedInsertStrNamedArgs() { + Pokemon pokemon = new Pokemon(301, "Ivysaur", Types.POISON, Types.GRASS); + long result = db.execute() + .createNamedInsert("insert-pokemon-named-arg") + .addParam("id", pokemon.id()).addParam("name", pokemon.name()) + .execute(); + verifyInsertPokemon(result, pokemon); + } + + @Override + public void testCreateNamedInsertStrOrderArgs() { + Pokemon pokemon = new Pokemon(302, "Venusaur", Types.POISON, Types.GRASS); + long result = db.execute() + .createNamedInsert("insert-pokemon-order-arg") + .addParam(pokemon.id()).addParam(pokemon.name()) + .execute(); + verifyInsertPokemon(result, pokemon); + } + + @Override + public void testCreateInsertNamedArgs() { + Pokemon pokemon = new Pokemon(303, "Magby", Types.FIRE); + String stmt = statements.get("insert-pokemon-named-arg"); + long result = db.execute() + .createInsert(stmt) + .addParam("id", pokemon.id()).addParam("name", pokemon.name()) + .execute(); + verifyInsertPokemon(result, pokemon); + } + + @Override + public void testCreateInsertOrderArgs() { + Pokemon pokemon = new Pokemon(304, "Magmar", Types.FIRE); + String stmt = statements.get("insert-pokemon-order-arg"); + long result = db.execute() + .createInsert(stmt) + .addParam(pokemon.id()).addParam(pokemon.name()) + .execute(); + verifyInsertPokemon(result, pokemon); + } + + @Override + public void testNamedInsertOrderArgs() { + Pokemon pokemon = new Pokemon(305, "Rattata", Types.NORMAL); + long result = db.execute().namedInsert("insert-pokemon-order-arg", pokemon.id(), pokemon.name()); + verifyInsertPokemon(result, pokemon); + } + + @Override + public void testInsertOrderArgs() { + Pokemon pokemon = new Pokemon(306, "Raticate", Types.NORMAL); + String stmt = statements.get("insert-pokemon-order-arg"); + long result = db.execute().insert(stmt, pokemon.id(), pokemon.name()); + verifyInsertPokemon(result, pokemon); + } + + @Override + public void testCreateNamedQueryStrStrOrderArgs() { + Pokemon expected = Pokemons.PIKACHU; + String stmt = statements.get("select-pokemon-order-arg"); + Stream rows = db.execute() + .createNamedQuery("select-pikachu", stmt) + .addParam(expected.name()) + .execute(); + + verifyPokemon(rows, expected); + } + + @Override + public void testCreateNamedQueryStrNamedArgs() { + Pokemon expected = Pokemons.RAICHU; + Stream rows = db.execute() + .createNamedQuery("select-pokemon-named-arg") + .addParam("name", expected.name()) + .execute(); + verifyPokemon(rows, expected); + } + + @Override + public void testCreateNamedQueryStrOrderArgs() { + Pokemon expected = Pokemons.MACHOP; + Stream rows = db.execute() + .createNamedQuery("select-pokemon-order-arg") + .addParam(expected.name()) + .execute(); + verifyPokemon(rows, expected); + } + + @Override + public void testCreateQueryNamedArgs() { + Pokemon expected = Pokemons.SNORLAX; + String stmt = statements.get("select-pokemon-named-arg"); + Stream rows = db.execute() + .createQuery(stmt) + .addParam("name", expected.name()) + .execute(); + verifyPokemon(rows, expected); + } + + @Override + public void testCreateQueryOrderArgs() { + Pokemon expected = Pokemons.CHARIZARD; + String stmt = statements.get("select-pokemon-order-arg"); + Stream rows = db.execute() + .createQuery(stmt) + .addParam(expected.name()) + .execute(); + verifyPokemon(rows, expected); + } + + @Override + public void testNamedQueryOrderArgs() { + Pokemon expected = Pokemons.MEOWTH; + Stream rows = db.execute() + .namedQuery("select-pokemon-order-arg", expected.name()); + verifyPokemon(rows, expected); + } + + @Override + public void testQueryOrderArgs() { + Pokemon expected = Pokemons.GYARADOS; + String stmt = statements.get("select-pokemon-order-arg"); + Stream rows = db.execute() + .query(stmt, expected.name()); + verifyPokemon(rows, expected); + } + + @Override + public void testCreateNamedUpdateStrStrNamedArgs() { + Pokemon orig = Pokemons.SPEAROW; + Pokemon updated = new Pokemon(orig.id(), "UpdatedSpearow", orig.types()); + String stmt = statements.get("update-pokemon-named-arg"); + long result = db.execute() + .createNamedUpdate("update-spearow", stmt) + .addParam("name", updated.name()).addParam("id", updated.id()) + .execute(); + verifyUpdatePokemon(result, updated); + } + + @Override + public void testCreateNamedUpdateStrNamedArgs() { + Pokemon orig = Pokemons.FEAROW; + Pokemon updated = new Pokemon(orig.id(), "UpdatedFearow", orig.types()); + long result = db.execute() + .createNamedUpdate("update-pokemon-named-arg") + .addParam("name", updated.name()).addParam("id", updated.id()) + .execute(); + verifyUpdatePokemon(result, updated); + } + + @Override + public void testCreateNamedUpdateStrOrderArgs() { + Pokemon orig = Pokemons.EKANS; + Pokemon updated = new Pokemon(orig.id(), "UpdatedEkans", orig.types()); + long result = db.execute() + .createNamedUpdate("update-pokemon-order-arg") + .addParam(updated.name()).addParam(updated.id()) + .execute(); + verifyUpdatePokemon(result, updated); + } + + @Override + public void testCreateUpdateNamedArgs() { + Pokemon orig = Pokemons.ARBOK; + Pokemon updated = new Pokemon(orig.id(), "UpdatedArbok", orig.types()); + String stmt = statements.get("update-pokemon-named-arg"); + long result = db.execute() + .createUpdate(stmt) + .addParam("name", updated.name()).addParam("id", updated.id()) + .execute(); + verifyUpdatePokemon(result, updated); + } + + @Override + public void testCreateUpdateOrderArgs() { + Pokemon orig = Pokemons.SANDSHREW; + Pokemon updated = new Pokemon(orig.id(), "UpdatedSandshrew", orig.types()); + String stmt = statements.get("update-pokemon-order-arg"); + long result = db.execute() + .createUpdate(stmt) + .addParam(updated.name()).addParam(updated.id()) + .execute(); + verifyUpdatePokemon(result, updated); + } + + @Override + public void testNamedUpdateNamedArgs() { + Pokemon orig = Pokemons.SANDSLASH; + Pokemon updated = new Pokemon(orig.id(), "UpdatedSandslash", orig.types()); + long result = db.execute() + .namedUpdate("update-pokemon-order-arg", updated.name(), updated.id()); + verifyUpdatePokemon(result, updated); + } + + @Override + public void testUpdateOrderArgs() { + Pokemon orig = Pokemons.DIGLETT; + Pokemon updated = new Pokemon(orig.id(), "UpdatedDiglett", orig.types()); + String stmt = statements.get("update-pokemon-order-arg"); + long result = db.execute() + .update(stmt, updated.name(), updated.id()); + verifyUpdatePokemon(result, updated); + } +} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/SimpleTests.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/SimpleTests.java new file mode 100644 index 00000000000..b9b3a935d45 --- /dev/null +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/SimpleTests.java @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.common; + +/** + * Simple test. + */ +public interface SimpleTests { + + /** + * Test set of basic JDBC delete calls. + */ + interface DeleteTest { + + /** + * Verify {@code createNamedDelete(String, String)} API method with ordered parameters. + */ + void testCreateNamedDeleteStrStrOrderArgs(); + + /** + * Verify {@code createNamedDelete(String)} API method with named parameters. + */ + void testCreateNamedDeleteStrNamedArgs(); + + /** + * Verify {@code createNamedDelete(String)} API method with ordered parameters. + */ + void testCreateNamedDeleteStrOrderArgs(); + + /** + * Verify {@code createDelete(String)} API method with named parameters. + */ + void testCreateDeleteNamedArgs(); + + /** + * Verify {@code createDelete(String)} API method with ordered parameters. + */ + void testCreateDeleteOrderArgs(); + + /** + * Verify {@code namedDelete(String)} API method with ordered parameters. + */ + void testNamedDeleteOrderArgs(); + + /** + * Verify {@code delete(String)} API method with ordered parameters. + */ + void testDeleteOrderArgs(); + } + + /** + * Test set of basic JDBC DML statement calls. + */ + interface DmlTest { + + /** + * Verify {@code createNamedDmlStatement(String, String)} API method with insert with named parameters. + */ + void testCreateNamedDmlWithInsertStrStrNamedArgs(); + + /** + * Verify {@code createNamedDmlStatement(String)} API method with insert with named parameters. + */ + void testCreateNamedDmlWithInsertStrNamedArgs(); + + /** + * Verify {@code createNamedDmlStatement(String)} API method with insert with ordered parameters. + */ + void testCreateNamedDmlWithInsertStrOrderArgs(); + + /** + * Verify {@code createDmlStatement(String)} API method with insert with named parameters. + */ + void testCreateDmlWithInsertNamedArgs(); + + /** + * Verify {@code createDmlStatement(String)} API method with insert with ordered parameters. + */ + void testCreateDmlWithInsertOrderArgs(); + + /** + * Verify {@code namedDml(String)} API method with insert with ordered parameters passed directly + * to the {@code insert} method. + */ + void testNamedDmlWithInsertOrderArgs(); + + /** + * Verify {@code dml(String)} API method with insert with ordered parameters passed directly + * to the {@code insert} method. + */ + void testDmlWithInsertOrderArgs(); + + /** + * Verify {@code createNamedDmlStatement(String, String)} API method with update with named parameters. + */ + void testCreateNamedDmlWithUpdateStrStrNamedArgs(); + + /** + * Verify {@code createNamedDmlStatement(String)} API method with update with named parameters. + */ + void testCreateNamedDmlWithUpdateStrNamedArgs(); + + /** + * Verify {@code createNamedDmlStatement(String)} API method with update with ordered parameters. + */ + void testCreateNamedDmlWithUpdateStrOrderArgs(); + + /** + * Verify {@code createDmlStatement(String)} API method with update with named parameters. + */ + void testCreateDmlWithUpdateNamedArgs(); + + /** + * Verify {@code createDmlStatement(String)} API method with update with ordered parameters. + */ + void testCreateDmlWithUpdateOrderArgs(); + + /** + * Verify {@code namedDml(String)} API method with update with ordered parameters passed directly + * to the {@code insert} method. + */ + void testNamedDmlWithUpdateOrderArgs(); + + /** + * Verify {@code dml(String)} API method with update with ordered parameters passed directly + * to the {@code insert} method. + */ + void testDmlWithUpdateOrderArgs(); + + /** + * Verify {@code createNamedDmlStatement(String, String)} API method with delete with ordered parameters. + */ + void testCreateNamedDmlWithDeleteStrStrOrderArgs(); + + /** + * Verify {@code createNamedDmlStatement(String)} API method with delete with named parameters. + */ + void testCreateNamedDmlWithDeleteStrNamedArgs(); + + /** + * Verify {@code createNamedDmlStatement(String)} API method with delete with ordered parameters. + */ + void testCreateNamedDmlWithDeleteStrOrderArgs(); + + /** + * Verify {@code createDmlStatement(String)} API method with delete with named parameters. + */ + void testCreateDmlWithDeleteNamedArgs(); + + /** + * Verify {@code createDmlStatement(String)} API method with delete with ordered parameters. + */ + void testCreateDmlWithDeleteOrderArgs(); + + /** + * Verify {@code namedDml(String)} API method with delete with ordered parameters. + */ + void testNamedDmlWithDeleteOrderArgs(); + + /** + * Verify {@code dml(String)} API method with delete with ordered parameters. + */ + void testDmlWithDeleteOrderArgs(); + } + + /** + * Test set of basic JDBC get calls. + */ + interface GetTest { + + /** + * Verify {@code createNamedGet(String, String)} API method with named parameters. + */ + void testCreateNamedGetStrStrNamedArgs(); + + /** + * Verify {@code createNamedGet(String)} API method with named parameters. + */ + void testCreateNamedGetStrNamedArgs(); + + /** + * Verify {@code createNamedGet(String)} API method with ordered parameters. + */ + void testCreateNamedGetStrOrderArgs(); + + /** + * Verify {@code createGet(String)} API method with named parameters. + */ + void testCreateGetNamedArgs(); + + /** + * Verify {@code createGet(String)} API method with ordered parameters. + */ + void testCreateGetOrderArgs(); + + /** + * Verify {@code namedGet(String)} API method with ordered parameters passed directly to the {@code query} method. + */ + void testNamedGetStrOrderArgs(); + + /** + * Verify {@code get(String)} API method with ordered parameters passed directly to the {@code query} method. + */ + void testGetStrOrderArgs(); + } + + /** + * Test set of basic JDBC inserts. + */ + interface InsertTest { + + /** + * Verify {@code createNamedInsert(String, String)} API method with named parameters. + */ + void testCreateNamedInsertStrStrNamedArgs(); + + /** + * Verify {@code createNamedInsert(String)} API method with named parameters. + */ + void testCreateNamedInsertStrNamedArgs(); + + /** + * Verify {@code createNamedInsert(String)} API method with ordered parameters. + */ + void testCreateNamedInsertStrOrderArgs(); + + /** + * Verify {@code createInsert(String)} API method with named parameters. + */ + void testCreateInsertNamedArgs(); + + /** + * Verify {@code createInsert(String)} API method with ordered parameters. + */ + void testCreateInsertOrderArgs(); + + /** + * Verify {@code namedInsert(String)} API method with ordered parameters passed directly to the {@code insert} method. + */ + void testNamedInsertOrderArgs(); + + /** + * Verify {@code insert(String)} API method with ordered parameters passed directly to the {@code insert} method. + */ + void testInsertOrderArgs(); + } + + /** + * Test set of basic JDBC queries. + */ + interface QueriesTest { + + /** + * Verify {@code createNamedQuery(String, String)} API method with ordered parameters. + */ + void testCreateNamedQueryStrStrOrderArgs(); + + /** + * Verify {@code createNamedQuery(String)} API method with named parameters. + */ + void testCreateNamedQueryStrNamedArgs(); + + /** + * Verify {@code createNamedQuery(String)} API method with ordered parameters. + */ + void testCreateNamedQueryStrOrderArgs(); + + /** + * Verify {@code createQuery(String)} API method with named parameters. + */ + void testCreateQueryNamedArgs(); + + /** + * Verify {@code createQuery(String)} API method with ordered parameters. + */ + void testCreateQueryOrderArgs(); + + /** + * Verify {@code namedQuery(String)} API method with ordered parameters passed directly to the {@code namedQuery} method. + */ + void testNamedQueryOrderArgs(); + + /** + * Verify {@code query(String)} API method with ordered parameters passed directly to the {@code query} method. + */ + void testQueryOrderArgs(); + } + + /** + * Test set of basic JDBC updates. + */ + interface UpdateTest { + + /** + * Verify {@code createNamedUpdate(String, String)} API method with named parameters. + */ + void testCreateNamedUpdateStrStrNamedArgs(); + + /** + * Verify {@code createNamedUpdate(String)} API method with named parameters. + */ + void testCreateNamedUpdateStrNamedArgs(); + + /** + * Verify {@code createNamedUpdate(String)} API method with ordered parameters. + */ + void testCreateNamedUpdateStrOrderArgs(); + + /** + * Verify {@code createUpdate(String)} API method with named parameters. + */ + void testCreateUpdateNamedArgs(); + + /** + * Verify {@code createUpdate(String)} API method with ordered parameters. + */ + void testCreateUpdateOrderArgs(); + + /** + * Verify {@code namedUpdate(String)} API method with named parameters. + */ + void testNamedUpdateNamedArgs(); + + /** + * Verify {@code update(String)} API method with ordered parameters. + */ + void testUpdateOrderArgs(); + } +} \ No newline at end of file diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/spi/SetupProvider.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/StatementTest.java similarity index 55% rename from tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/spi/SetupProvider.java rename to tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/StatementTest.java index d3c110cb658..d3a2eb73106 100644 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/spi/SetupProvider.java +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/StatementTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2024 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. @@ -13,23 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.helidon.tests.integration.dbclient.common.spi; - -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; - -public interface SetupProvider { - - /** - * Provide root {@Config} instance for the tests. - */ - Config config(); - - /** - * Provide {@link DbClient} instance for the tests. - * - * @return the {@link DbClient} instance - */ - DbClient dbClient(); +package io.helidon.tests.integration.dbclient.common; +/** + * Statement tests. + */ +public interface StatementTest extends StatementTests.StmtExceptionalTest, + StatementTests.StmtGetTest, + StatementTests.StmtQueryTest, + StatementTests.StmtDmlTest { } diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/StatementTestImpl.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/StatementTestImpl.java new file mode 100644 index 00000000000..92d2a813fdf --- /dev/null +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/StatementTestImpl.java @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.common; + +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +import io.helidon.config.Config; +import io.helidon.dbclient.DbClient; +import io.helidon.dbclient.DbRow; +import io.helidon.tests.integration.dbclient.common.model.Pokemon; +import io.helidon.tests.integration.dbclient.common.model.Pokemons; +import io.helidon.tests.integration.dbclient.common.model.Range; +import io.helidon.tests.integration.dbclient.common.model.Types; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.notNullValue; + +/** + * Actual implementation of {@link StatementTests}. + */ +public final class StatementTestImpl extends AbstractTestImpl implements StatementTest { + + /** + * Create a new instance. + * + * @param db db client + * @param config config + */ + public StatementTestImpl(DbClient db, Config config) { + super(db, config); + } + + @Override + public void testCreateNamedQueryNonExistentStmt() { + try { + List ignored = db.execute() + .createNamedQuery("select-pokemons-not-exists") + .execute() + .toList(); + throw new AssertionError("Execution of non existing statement shall cause an exception to be thrown."); + } catch (Throwable ex) { + // expected + } + } + + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithoutArgs() { + try { + List ignored = db.execute() + .createNamedQuery("select-pokemons-error-arg") + .execute() + .toList(); + throw new AssertionError("Execution of query with both named and ordered parameters without passing any shall fail."); + } catch (Throwable ex) { + // expected + } + } + + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithArgs() { + try { + Pokemon pokemon = Pokemons.CHARIZARD; + List ignored = db.execute() + .createNamedQuery("select-pokemons-error-arg") + .addParam("id", pokemon.id()) + .addParam(pokemon.name()) + .execute() + .toList(); + throw new AssertionError("Execution of query with both named and ordered parameters without passing them shall fail" + + "."); + } catch (Throwable ex) { + // expected + } + } + + @Override + public void testCreateNamedQueryNamedArgsSetOrderArg() { + try { + Pokemon pokemon = Pokemons.CHARIZARD; + List ignored = db.execute() + .createNamedQuery("select-pokemon-named-arg") + .addParam(pokemon.name()) + .execute() + .toList(); + throw new AssertionError("Execution of query with named parameter with passing ordered parameter value shall fail."); + } catch (Throwable ex) { + // expected + } + } + + @Override + public void testCreateNamedQueryOrderArgsSetNamedArg() { + try { + Pokemon pokemon = Pokemons.MEOWTH; + List ignored = db.execute() + .createNamedQuery("select-pokemon-order-arg") + .addParam("name", pokemon.name()) + .execute() + .toList(); + throw new AssertionError("Execution of query with ordered parameter with passing named parameter value shall fail."); + } catch (Throwable ex) { + // expected + } + } + + @Override + public void testGetArrayParams() { + DbRow row = db.execute() + .createNamedGet("select-pokemons-idrng-order-arg") + .params(1, 3) + .execute() + .orElse(null); + verifyPokemonsIdRange(row, 1, 3); + } + + @Override + public void testGetListParams() { + DbRow row = db.execute() + .createNamedGet("select-pokemons-idrng-order-arg") + .params(List.of(2, 4)) + .execute() + .orElse(null); + verifyPokemonsIdRange(row, 2, 4); + } + + @Override + public void testGetMapParams() { + DbRow row = db.execute() + .createNamedGet("select-pokemons-idrng-named-arg") + .params(Map.of( + "idmin", 3, + "idmax", 5)) + .execute() + .orElse(null); + verifyPokemonsIdRange(row, 3, 5); + } + + @Override + public void testGetOrderParam() { + DbRow row = db.execute() + .createNamedGet("select-pokemons-idrng-order-arg") + .addParam(4) + .addParam(6) + .execute() + .orElse(null); + verifyPokemonsIdRange(row, 4, 6); + } + + @Override + public void testGetNamedParam() { + DbRow row = db.execute() + .createNamedGet("select-pokemons-idrng-named-arg") + .addParam("idmin", 5) + .addParam("idmax", 7) + .execute() + .orElse(null); + verifyPokemonsIdRange(row, 5, 7); + } + + @Override + public void testGetMappedNamedParam() { + Range range = new Range(0, 2); + DbRow row = db.execute() + .createNamedGet("select-pokemons-idrng-named-arg") + .namedParam(range) + .execute() + .orElse(null); + verifyPokemonsIdRange(row, 0, 2); + } + + @Override + public void testGetMappedOrderParam() { + Range range = new Range(6, 8); + DbRow row = db.execute() + .createNamedGet("select-pokemons-idrng-order-arg") + .indexedParam(range) + .execute() + .orElse(null); + verifyPokemonsIdRange(row, 6, 8); + } + + @Override + public void testQueryArrayParams() { + Stream rows = db.execute() + .createNamedQuery("select-pokemons-idrng-order-arg") + .params(1, 7) + .execute(); + + verifyPokemonsIdRange(rows); + } + + @Override + public void testQueryListParams() { + Stream rows = db.execute() + .createNamedQuery("select-pokemons-idrng-order-arg") + .params(List.of(1, 7)) + .execute(); + + verifyPokemonsIdRange(rows); + } + + @Override + public void testQueryMapParams() { + Stream rows = db.execute() + .createNamedQuery("select-pokemons-idrng-named-arg") + .params(Map.of( + "idmin", 1, + "idmax", 7)) + .execute(); + + verifyPokemonsIdRange(rows); + } + + @Override + public void testQueryMapMissingParams() { + Stream rows = db.execute() + .createNamedQuery("select-pokemons-idname-named-arg") + .params(Map.of("id", 1)) + .execute(); + assertThat(rows, notNullValue()); + List rowsList = rows.toList(); + assertThat(rowsList, hasSize(0)); + } + + @Override + public void testQueryOrderParam() { + Stream rows = db.execute() + .createNamedQuery("select-pokemons-idrng-order-arg") + .addParam(1) + .addParam(7) + .execute(); + + verifyPokemonsIdRange(rows); + } + + @Override + public void testQueryNamedParam() { + Stream rows = db.execute() + .createNamedQuery("select-pokemons-idrng-named-arg") + .addParam("idmin", 1) + .addParam("idmax", 7) + .execute(); + + verifyPokemonsIdRange(rows); + } + + @Override + public void testQueryMappedNamedParam() { + Range range = new Range(1, 7); + Stream rows = db.execute() + .createNamedQuery("select-pokemons-idrng-named-arg") + .namedParam(range) + .execute(); + + verifyPokemonsIdRange(rows); + } + + @Override + public void testQueryMappedOrderParam() { + Range range = new Range(1, 7); + Stream rows = db.execute() + .createNamedQuery("select-pokemons-idrng-order-arg") + .indexedParam(range) + .execute(); + + verifyPokemonsIdRange(rows); + } + + @Override + public void testDmlArrayParams() { + Pokemon orig = Pokemons.SHINX; + Pokemon updated = new Pokemon(orig.id(), "UpdatedShinx", Types.ELECTRIC); + long result = db.execute() + .createNamedDmlStatement("update-pokemon-order-arg") + .params(updated.name(), updated.id()) + .execute(); + verifyUpdatePokemon(result, updated); + } + + @Override + public void testDmlListParams() { + Pokemon orig = Pokemons.LUXIO; + Pokemon updated = new Pokemon(orig.id(), "UpdatedLuxio", Types.ELECTRIC); + long result = db.execute() + .createNamedDmlStatement("update-pokemon-order-arg") + .params(List.of(updated.name(), updated.id())) + .execute(); + verifyUpdatePokemon(result, updated); + } + + @Override + public void testDmlMapParams() { + Pokemon orig = Pokemons.LUXRAY; + Pokemon updated = new Pokemon(orig.id(), "UpdatedLuxray", Types.ELECTRIC); + long result = db.execute() + .createNamedDmlStatement("update-pokemon-named-arg") + .params(Map.of( + "name", updated.name(), + "id", updated.id())) + .execute(); + verifyUpdatePokemon(result, updated); + } + + @Override + public void testDmlOrderParam() { + Pokemon orig = Pokemons.KRICKETOT; + Pokemon updated = new Pokemon(orig.id(), "UpdatedKricketot", Types.BUG); + long result = db.execute() + .createNamedDmlStatement("update-pokemon-order-arg") + .addParam(updated.name()) + .addParam(updated.id()) + .execute(); + verifyUpdatePokemon(result, updated); + } + + @Override + public void testDmlNamedParam() { + Pokemon orig = Pokemons.KRICKETUNE; + Pokemon updated = new Pokemon(orig.id(), "UpdatedKricketune", Types.BUG); + long result = db.execute() + .createNamedDmlStatement("update-pokemon-named-arg") + .addParam("name", updated.name()) + .addParam("id", updated.id()) + .execute(); + verifyUpdatePokemon(result, updated); + } + + @Override + public void testDmlMappedNamedParam() { + Pokemon orig = Pokemons.PHIONE; + Pokemon updated = new Pokemon(orig.id(), "UpdatedPhione", Types.NORMAL, Types.FLYING); + long result = db.execute() + .createNamedDmlStatement("update-pokemon-named-arg") + .namedParam(updated) + .execute(); + verifyUpdatePokemon(result, updated); + } + + @Override + public void testDmlMappedOrderParam() { + Pokemon orig = Pokemons.CHATOT; + Pokemon updated = new Pokemon(orig.id(), "UpdatedChatot", Types.WATER); + long result = db.execute() + .createNamedDmlStatement("update-pokemon-order-arg") + .indexedParam(updated) + .execute(); + verifyUpdatePokemon(result, updated); + } + + private void verifyPokemonsIdRange(Stream rows) { + Map valid = range(1, 7); + + // Compare result with valid data + assertThat(rows, notNullValue()); + List rowsList = rows.toList(); + assertThat(rowsList, hasSize(valid.size())); + for (DbRow row : rowsList) { + int id = row.column(1).get(Integer.class); + String name = row.column(2).get(String.class); + assertThat(valid.containsKey(id), equalTo(true)); + assertThat(name, equalTo(valid.get(id).name())); + } + } +} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/StatementTests.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/StatementTests.java new file mode 100644 index 00000000000..b5602f49221 --- /dev/null +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/StatementTests.java @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.common; + +/** + * Statement tests. + */ +public interface StatementTests { + + /** + * Test exceptional states. + */ + interface StmtExceptionalTest { + + /** + * Verify that execution of query with non-existing named statement throws an exception. + */ + void testCreateNamedQueryNonExistentStmt(); + + /** + * Verify that execution of query with both named and ordered arguments throws an exception. + */ + void testCreateNamedQueryNamedAndOrderArgsWithoutArgs(); + + /** + * Verify that execution of query with both named and ordered arguments throws an exception. + */ + void testCreateNamedQueryNamedAndOrderArgsWithArgs(); + + /** + * Verify that execution of query with named arguments throws an exception while trying to set ordered argument. + */ + void testCreateNamedQueryNamedArgsSetOrderArg(); + + /** + * Verify that execution of query with ordered arguments throws an exception while trying to set named argument. + */ + void testCreateNamedQueryOrderArgsSetNamedArg(); + } + + /** + * Test DbStatementGet methods. + */ + interface StmtGetTest { + + /** + * Verify {@code params(Object... parameters)} parameters setting method. + */ + void testGetArrayParams(); + + /** + * Verify {@code params(List)} parameters setting method. + */ + void testGetListParams(); + + /** + * Verify {@code params(Map)} parameters setting method. + */ + void testGetMapParams(); + + /** + * Verify {@code addParam(Object parameter)} parameters setting method. + */ + void testGetOrderParam(); + + /** + * Verify {@code addParam(String name, Object parameter)} parameters setting method. + */ + void testGetNamedParam(); + + /** + * Verify {@code namedParam(Object parameters)} mapped parameters setting method. + */ + void testGetMappedNamedParam(); + + /** + * Verify {@code indexedParam(Object parameters)} mapped parameters setting method. + */ + void testGetMappedOrderParam(); + } + + /** + * Test DbStatementQuery methods. + */ + interface StmtQueryTest { + + /** + * Verify {@code params(Object... parameters)} parameters setting method. + */ + void testQueryArrayParams(); + + /** + * Verify {@code params(List)} parameters setting method. + */ + void testQueryListParams(); + + /** + * Verify {@code params(Map)} parameters setting method. + */ + void testQueryMapParams(); + + /** + * Verify {@code params(Map)} with missing parameters. + */ + void testQueryMapMissingParams(); + + /** + * Verify {@code addParam(Object parameter)} parameters setting method. + */ + void testQueryOrderParam(); + + /** + * Verify {@code addParam(String name, Object parameter)} parameters setting method. + */ + void testQueryNamedParam(); + + /** + * Verify {@code namedParam(Object parameters)} mapped parameters setting method. + */ + void testQueryMappedNamedParam(); + + /** + * Verify {@code indexedParam(Object parameters)} mapped parameters setting method. + */ + void testQueryMappedOrderParam(); + } + + /** + * Test DbStatementDml methods. + */ + interface StmtDmlTest { + + /** + * Verify {@code params(Object... parameters)} parameters setting method. + */ + void testDmlArrayParams(); + + /** + * Verify {@code params(List)} parameters setting method. + */ + void testDmlListParams(); + + /** + * Verify {@code params(Map)} parameters setting method. + */ + void testDmlMapParams(); + + /** + * Verify {@code addParam(Object parameter)} parameters setting method. + */ + void testDmlOrderParam(); + + /** + * Verify {@code addParam(String name, Object parameter)} parameters setting method. + */ + void testDmlNamedParam(); + + /** + * Verify {@code namedParam(Object parameters)} mapped parameters setting method. + */ + void testDmlMappedNamedParam(); + + /** + * Verify {@code indexedParam(Object parameters)} mapped parameters setting method. + */ + void testDmlMappedOrderParam(); + } +} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/TestService.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/TestService.java new file mode 100644 index 00000000000..15e78a130a7 --- /dev/null +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/TestService.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.common; + +import java.lang.reflect.InvocationTargetException; + +import io.helidon.common.context.Contexts; +import io.helidon.config.Config; +import io.helidon.dbclient.DbClient; +import io.helidon.http.InternalServerException; +import io.helidon.http.NotFoundException; +import io.helidon.webclient.http1.Http1Client; +import io.helidon.webserver.WebServer; +import io.helidon.webserver.http.HttpRules; +import io.helidon.webserver.http.HttpService; +import io.helidon.webserver.http.ServerRequest; +import io.helidon.webserver.http.ServerResponse; + +import static java.util.Objects.requireNonNullElse; + +/** + * Service to expose all tests. + */ +final class TestService implements HttpService { + + private final TransactionTestImpl transaction; + private final StatementTestImpl statement; + private final SimpleTestImpl simple; + private final MiscTestImpl misc; + private final ObservabilityTestImpl observability; + + TestService(DbClient db, Config config) { + transaction = new TransactionTestImpl(db, config); + statement = new StatementTestImpl(db, config); + simple = new SimpleTestImpl(db, config); + misc = new MiscTestImpl(db, config); + observability = new ObservabilityTestImpl(db, config, this::client); + } + + private Http1Client client() { + return Contexts.context() + .flatMap(c -> c.get(WebServer.class)) + .map(server -> Http1Client.builder() + .baseUri("http://localhost:" + server.port()) + .build()) + .orElseThrow(() -> new IllegalStateException("Unable to get server instance from current context")); + } + + @Override + public void routing(HttpRules rules) { + rules + .get("/transaction/{testName}", this::transaction) + .get("/statement/{testName}", this::statement) + .get("/simple/{testName}", this::simple) + .get("/misc/{testName}", this::misc) + .get("/observability/{testName}", this::observability); + } + + private void transaction(ServerRequest req, ServerResponse res) { + invokeTest(transaction, req, res); + } + + private void statement(ServerRequest req, ServerResponse res) { + invokeTest(statement, req, res); + } + + private void simple(ServerRequest req, ServerResponse res) { + invokeTest(simple, req, res); + + } + + private void misc(ServerRequest req, ServerResponse res) { + invokeTest(misc, req, res); + } + + private void observability(ServerRequest req, ServerResponse res) { + invokeTest(observability, req, res); + } + + private static void invokeTest(Object o, ServerRequest req, ServerResponse res) { + String testName = req.path().pathParameters().get("testName"); + try { + o.getClass().getMethod(testName).invoke(o); + res.send("OK"); + } catch (IllegalAccessException ex) { + throw new InternalServerException(ex.getMessage(), ex); + } catch (InvocationTargetException ex) { + requireNonNullElse(ex.getCause(), ex).printStackTrace(System.err); + throw new InternalServerException(ex.getMessage(), ex); + } catch (NoSuchMethodException ignored) { + throw new NotFoundException("Test not found: " + testName); + } + } +} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/TransactionTest.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/TransactionTest.java new file mode 100644 index 00000000000..101d26a2865 --- /dev/null +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/TransactionTest.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.common; + +/** + * Test set of basic JDBC delete calls in transaction. + */ +public interface TransactionTest extends TransactionTests.TxDeleteTest, + TransactionTests.TxExceptionalStmtTest, + TransactionTests.TxGetTest, + TransactionTests.TxInsertTest, + TransactionTests.TxQueriesTest, + TransactionTests.TxUpdateTest { +} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/TransactionTestImpl.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/TransactionTestImpl.java new file mode 100644 index 00000000000..504463395e6 --- /dev/null +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/TransactionTestImpl.java @@ -0,0 +1,559 @@ +/* + * Copyright (c) 2019, 2024 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.tests.integration.dbclient.common; + +import java.util.List; + +import io.helidon.config.Config; +import io.helidon.dbclient.DbClient; +import io.helidon.dbclient.DbRow; +import io.helidon.dbclient.DbTransaction; +import io.helidon.tests.integration.dbclient.common.model.Pokemon; +import io.helidon.tests.integration.dbclient.common.model.Pokemons; +import io.helidon.tests.integration.dbclient.common.model.Types; + +/** + * Actual implementation of {@link TransactionTests}. + */ +public final class TransactionTestImpl extends AbstractTestImpl implements TransactionTest { + + /** + * Create a new instance. + * + * @param db db client + * @param config config + */ + public TransactionTestImpl(DbClient db, Config config) { + super(db, config); + } + + @Override + public void testCreateNamedDeleteStrStrOrderArgs() { + Pokemon pokemon = Pokemons.OMANYTE; + String stmt = statements.get("delete-pokemon-order-arg"); + DbTransaction tx = db.transaction(); + long result = tx + .createNamedDelete("delete-rayquaza", stmt) + .addParam(pokemon.id()) + .execute(); + tx.commit(); + verifyDeletePokemon(result, pokemon); + } + + @Override + public void testCreateNamedDeleteStrNamedArgs() { + Pokemon pokemon = Pokemons.OMASTAR; + DbTransaction tx = db.transaction(); + long result = tx + .createNamedDelete("delete-pokemon-named-arg") + .addParam("id", pokemon.id()) + .execute(); + tx.commit(); + verifyDeletePokemon(result, pokemon); + } + + @Override + public void testCreateNamedDeleteStrOrderArgs() { + Pokemon pokemon = Pokemons.KABUTO; + DbTransaction tx = db.transaction(); + long result = tx + .createNamedDelete("delete-pokemon-order-arg") + .addParam(pokemon.id()) + .execute(); + tx.commit(); + verifyDeletePokemon(result, pokemon); + } + + @Override + public void testCreateDeleteNamedArgs() { + Pokemon pokemon = Pokemons.KABUTOPS; + String stmt = statements.get("delete-pokemon-named-arg"); + DbTransaction tx = db.transaction(); + long result = tx + .createDelete(stmt) + .addParam("id", pokemon.id()) + .execute(); + tx.commit(); + verifyDeletePokemon(result, pokemon); + } + + @Override + public void testCreateDeleteOrderArgs() { + Pokemon pokemon = Pokemons.CHIKORITA; + String stmt = statements.get("delete-pokemon-order-arg"); + DbTransaction tx = db.transaction(); + long result = tx + .createDelete(stmt) + .addParam(pokemon.id()) + .execute(); + tx.commit(); + verifyDeletePokemon(result, pokemon); + } + + @Override + public void testNamedDeleteOrderArgs() { + Pokemon pokemon = Pokemons.BAYLEEF; + DbTransaction tx = db.transaction(); + long result = tx + .namedDelete("delete-pokemon-order-arg", pokemon.id()); + tx.commit(); + verifyDeletePokemon(result, pokemon); + } + + @Override + public void testDeleteOrderArgs() { + Pokemon pokemon = Pokemons.MEGANIUM; + String stmt = statements.get("delete-pokemon-order-arg"); + DbTransaction tx = db.transaction(); + long result = tx + .delete(stmt, pokemon.id()); + tx.commit(); + verifyDeletePokemon(result, pokemon); + } + + @Override + public void testCreateNamedQueryNonExistentStmt() { + try { + DbTransaction tx = db.transaction(); + List ignored = tx.createNamedQuery("select-pokemons-not-exists") + .execute() + .toList(); + tx.commit(); + throw new AssertionError("Execution of non existing statement shall cause an exception to be thrown."); + } catch (Throwable ex) { + // expected + } + } + + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithoutArgs() { + try { + DbTransaction tx = db.transaction(); + List ignored = tx.createNamedQuery("select-pokemons-error-arg") + .execute() + .toList(); + tx.commit(); + throw new AssertionError("Execution of query with both named and ordered parameters without passing any shall fail."); + } catch (Throwable ex) { + // expected + } + } + + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithArgs() { + try { + DbTransaction tx = db.transaction(); + List ignored = tx.createNamedQuery("select-pokemons-error-arg") + .addParam("id", 6789) + .addParam("a-name") + .execute() + .toList(); + tx.commit(); + throw new AssertionError("Execution of query with both named and ordered parameters without passing them shall fail" + + "."); + } catch (Throwable ex) { + // expected + } + } + + @Override + public void testCreateNamedQueryNamedArgsSetOrderArg() { + try { + DbTransaction tx = db.transaction(); + List ignored = tx.createNamedQuery("select-pokemon-named-arg") + .addParam("a-name") + .execute() + .toList(); + tx.commit(); + throw new AssertionError("Execution of query with named parameter with passing ordered parameter value shall fail."); + } catch (Throwable ex) { + // expected + } + } + + @Override + public void testCreateNamedQueryOrderArgsSetNamedArg() { + try { + DbTransaction tx = db.transaction(); + List ignored = tx.createNamedQuery("select-pokemon-order-arg") + .addParam("name", "a-name") + .execute() + .toList(); + tx.commit(); + throw new AssertionError("Execution of query with ordered parameter with passing named parameter value shall fail."); + } catch (Throwable ex) { + // expected + } + } + + @Override + public void testCreateNamedGetStrStrNamedArgs() { + Pokemon expected = Pokemons.PIKACHU; + String stmt = statements.get("select-pokemon-named-arg"); + DbTransaction tx = db.transaction(); + DbRow row = tx + .createNamedGet("select-pikachu", stmt) + .addParam("name", expected.name()) + .execute() + .orElse(null); + tx.commit(); + verifyPokemon(row, expected); + } + + @Override + public void testCreateNamedGetStrNamedArgs() { + Pokemon expected = Pokemons.RAICHU; + DbTransaction tx = db.transaction(); + DbRow row = tx + .createNamedGet("select-pokemon-named-arg") + .addParam("name", expected.name()) + .execute() + .orElse(null); + tx.commit(); + + verifyPokemon(row, expected); + } + + @Override + public void testCreateNamedGetStrOrderArgs() { + Pokemon expected = Pokemons.MACHOP; + DbTransaction tx = db.transaction(); + DbRow row = tx + .createNamedGet("select-pokemon-order-arg") + .addParam(expected.name()) + .execute() + .orElse(null); + tx.commit(); + + verifyPokemon(row, expected); + } + + @Override + public void testCreateGetNamedArgs() { + Pokemon expected = Pokemons.SNORLAX; + String stmt = statements.get("select-pokemon-named-arg"); + DbTransaction tx = db.transaction(); + DbRow row = tx + .createGet(stmt) + .addParam("name", expected.name()) + .execute() + .orElse(null); + tx.commit(); + + verifyPokemon(row, expected); + } + + @Override + public void testCreateGetOrderArgs() { + Pokemon expected = Pokemons.CHARIZARD; + String stmt = statements.get("select-pokemon-order-arg"); + DbTransaction tx = db.transaction(); + DbRow row = tx + .createGet(stmt) + .addParam(expected.name()) + .execute() + .orElse(null); + tx.commit(); + + verifyPokemon(row, expected); + } + + @Override + public void testNamedGetStrOrderArgs() { + Pokemon expected = Pokemons.MEOWTH; + DbTransaction tx = db.transaction(); + DbRow row = tx + .namedGet("select-pokemon-order-arg", expected.name()) + .orElse(null); + tx.commit(); + + verifyPokemon(row, expected); + } + + @Override + public void testGetStrOrderArgs() { + Pokemon expected = Pokemons.GYARADOS; + String stmt = statements.get("select-pokemon-order-arg"); + DbTransaction tx = db.transaction(); + DbRow row = tx + .get(stmt, expected.name()) + .orElse(null); + tx.commit(); + + verifyPokemon(row, expected); + } + + @Override + public void testCreateNamedInsertStrStrNamedArgs() { + Pokemon pokemon = new Pokemon(85, "Sentret", Types.NORMAL); + String stmt = statements.get("insert-pokemon-named-arg"); + DbTransaction tx = db.transaction(); + long result = tx + .createNamedInsert("insert-bulbasaur", stmt) + .addParam("id", pokemon.id()).addParam("name", pokemon.name()).execute(); + tx.commit(); + verifyInsertPokemon(result, pokemon); + } + + @Override + public void testCreateNamedInsertStrNamedArgs() { + Pokemon pokemon = new Pokemon(86, "Furret", Types.NORMAL); + DbTransaction tx = db.transaction(); + long result = tx + .createNamedInsert("insert-pokemon-named-arg") + .addParam("id", pokemon.id()).addParam("name", pokemon.name()).execute(); + tx.commit(); + verifyInsertPokemon(result, pokemon); + } + + @Override + public void testCreateNamedInsertStrOrderArgs() { + Pokemon pokemon = new Pokemon(87, "Chinchou", Types.WATER, Types.ELECTRIC); + DbTransaction tx = db.transaction(); + long result = tx + .createNamedInsert("insert-pokemon-order-arg") + .addParam(pokemon.id()).addParam(pokemon.name()).execute(); + tx.commit(); + verifyInsertPokemon(result, pokemon); + } + + @Override + public void testCreateInsertNamedArgs() { + Pokemon pokemon = new Pokemon(88, "Lanturn", Types.WATER, Types.ELECTRIC); + String stmt = statements.get("insert-pokemon-named-arg"); + DbTransaction tx = db.transaction(); + long result = tx + .createInsert(stmt) + .addParam("id", pokemon.id()).addParam("name", pokemon.name()).execute(); + tx.commit(); + verifyInsertPokemon(result, pokemon); + } + + @Override + public void testCreateInsertOrderArgs() { + Pokemon pokemon = new Pokemon(89, "Swinub", Types.GROUND, Types.ICE); + String stmt = statements.get("insert-pokemon-order-arg"); + DbTransaction tx = db.transaction(); + long result = tx + .createInsert(stmt) + .addParam(pokemon.id()).addParam(pokemon.name()).execute(); + tx.commit(); + verifyInsertPokemon(result, pokemon); + } + + @Override + public void testNamedInsertOrderArgs() { + Pokemon pokemon = new Pokemon(90, "Piloswine", Types.GROUND, Types.ICE); + DbTransaction tx = db.transaction(); + long result = tx + .namedInsert("insert-pokemon-order-arg", pokemon.id(), pokemon.name()); + tx.commit(); + verifyInsertPokemon(result, pokemon); + } + + @Override + public void testInsertOrderArgs() { + Pokemon pokemon = new Pokemon(91, "Mamoswine", Types.GROUND, Types.ICE); + String stmt = statements.get("insert-pokemon-order-arg"); + DbTransaction tx = db.transaction(); + long result = tx + .insert(stmt, pokemon.id(), pokemon.name()); + tx.commit(); + verifyInsertPokemon(result, pokemon); + } + + @Override + public void testCreateNamedQueryStrStrOrderArgs() { + Pokemon expected = Pokemons.PIKACHU; + String stmt = statements.get("select-pokemon-order-arg"); + DbTransaction tx = db.transaction(); + List rows = tx + .createNamedQuery("select-pikachu", stmt) + .addParam(expected.name()) + .execute() + .toList(); + tx.commit(); + verifyPokemon(rows, expected); + } + + @Override + public void testCreateNamedQueryStrNamedArgs() { + Pokemon expected = Pokemons.RAICHU; + DbTransaction tx = db.transaction(); + List rows = tx + .createNamedQuery("select-pokemon-named-arg") + .addParam("name", expected.name()) + .execute() + .toList(); + tx.commit(); + verifyPokemon(rows, expected); + } + + @Override + public void testCreateNamedQueryStrOrderArgs() { + Pokemon expected = Pokemons.MACHOP; + DbTransaction tx = db.transaction(); + List rows = tx + .createNamedQuery("select-pokemon-order-arg") + .addParam(expected.name()) + .execute() + .toList(); + tx.commit(); + verifyPokemon(rows, expected); + } + + @Override + public void testCreateQueryNamedArgs() { + Pokemon expected = Pokemons.SNORLAX; + String stmt = statements.get("select-pokemon-named-arg"); + DbTransaction tx = db.transaction(); + List rows = tx + .createQuery(stmt) + .addParam("name", expected.name()) + .execute() + .toList(); + tx.commit(); + verifyPokemon(rows, expected); + } + + @Override + public void testCreateQueryOrderArgs() { + Pokemon expected = Pokemons.CHARIZARD; + String stmt = statements.get("select-pokemon-order-arg"); + DbTransaction tx = db.transaction(); + List rows = tx + .createQuery(stmt) + .addParam(expected.name()) + .execute() + .toList(); + tx.commit(); + verifyPokemon(rows, expected); + } + + @Override + public void testNamedQueryOrderArgs() { + Pokemon expected = Pokemons.MEOWTH; + DbTransaction tx = db.transaction(); + List rows = tx + .namedQuery("select-pokemon-order-arg", expected.name()) + .toList(); + tx.commit(); + verifyPokemon(rows, expected); + } + + @Override + public void testQueryOrderArgs() { + Pokemon expected = Pokemons.GYARADOS; + String stmt = statements.get("select-pokemon-order-arg"); + DbTransaction tx = db.transaction(); + List rows = tx + .query(stmt, expected.name()) + .toList(); + tx.commit(); + verifyPokemon(rows, expected); + } + + @Override + public void testCreateNamedUpdateStrStrNamedArgs() { + Pokemon orig = Pokemons.TEDDIURSA; + Pokemon updated = new Pokemon(orig.id(), "UpdatedTeddiursa", orig.types()); + String stmt = statements.get("update-pokemon-named-arg"); + DbTransaction tx = db.transaction(); + long result = tx + .createNamedUpdate("update-pokemon-named-arg", stmt) + .addParam("name", updated.name()).addParam("id", updated.id()) + .execute(); + tx.commit(); + verifyUpdatePokemon(result, updated); + } + + @Override + public void testCreateNamedUpdateStrNamedArgs() { + Pokemon orig = Pokemons.URSARING; + Pokemon updated = new Pokemon(orig.id(), "UpdatedUrsaring", orig.types()); + DbTransaction tx = db.transaction(); + long result = tx + .createNamedUpdate("update-pokemon-named-arg") + .addParam("name", updated.name()).addParam("id", updated.id()) + .execute(); + tx.commit(); + verifyUpdatePokemon(result, updated); + } + + @Override + public void testCreateNamedUpdateStrOrderArgs() { + Pokemon orig = Pokemons.SLUGMA; + Pokemon updated = new Pokemon(orig.id(), "UpdatedSlugma", orig.types()); + DbTransaction tx = db.transaction(); + long result = tx + .createNamedUpdate("update-pokemon-order-arg") + .addParam(updated.name()).addParam(updated.id()) + .execute(); + tx.commit(); + verifyUpdatePokemon(result, updated); + } + + @Override + public void testCreateUpdateNamedArgs() { + Pokemon orig = Pokemons.MAGCARGO; + Pokemon updated = new Pokemon(orig.id(), "UpdatedMagcargo", orig.types()); + String stmt = statements.get("update-pokemon-named-arg"); + DbTransaction tx = db.transaction(); + long result = tx + .createUpdate(stmt) + .addParam("name", updated.name()).addParam("id", updated.id()) + .execute(); + tx.commit(); + verifyUpdatePokemon(result, updated); + } + + @Override + public void testCreateUpdateOrderArgs() { + Pokemon orig = Pokemons.LOTAD; + Pokemon updated = new Pokemon(orig.id(), "UpdatedLotad", orig.types()); + String stmt = statements.get("update-pokemon-order-arg"); + DbTransaction tx = db.transaction(); + long result = tx + .createUpdate(stmt) + .addParam(updated.name()).addParam(updated.id()) + .execute(); + tx.commit(); + verifyUpdatePokemon(result, updated); + } + + @Override + public void testNamedUpdateNamedArgs() { + Pokemon orig = Pokemons.LUDICOLO; + Pokemon updated = new Pokemon(orig.id(), "UpdatedLudicolo", orig.types()); + DbTransaction tx = db.transaction(); + long result = tx + .namedUpdate("update-pokemon-order-arg", updated.name(), updated.id()); + tx.commit(); + verifyUpdatePokemon(result, updated); + } + + @Override + public void testUpdateOrderArgs() { + Pokemon orig = Pokemons.LOMBRE; + Pokemon updated = new Pokemon(orig.id(), "UpdatedLombre", orig.types()); + String stmt = statements.get("update-pokemon-order-arg"); + DbTransaction tx = db.transaction(); + long result = tx + .update(stmt, updated.name(), updated.id()); + tx.commit(); + verifyUpdatePokemon(result, updated); + } +} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/TransactionTests.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/TransactionTests.java new file mode 100644 index 00000000000..a72aa0194ff --- /dev/null +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/TransactionTests.java @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.common; + +/** + * Test set of basic JDBC delete calls in transaction. + */ +public interface TransactionTests { + + /** + * Test set of basic JDBC delete calls in transaction. + */ + interface TxDeleteTest { + + /** + * Verify {@code createNamedDelete(String, String)} API method with ordered parameters. + */ + void testCreateNamedDeleteStrStrOrderArgs(); + + /** + * Verify {@code createNamedDelete(String)} API method with named parameters. + */ + void testCreateNamedDeleteStrNamedArgs(); + + /** + * Verify {@code createNamedDelete(String)} API method with ordered parameters. + */ + void testCreateNamedDeleteStrOrderArgs(); + + /** + * Verify {@code createDelete(String)} API method with named parameters. + */ + void testCreateDeleteNamedArgs(); + + /** + * Verify {@code createDelete(String)} API method with ordered parameters. + */ + void testCreateDeleteOrderArgs(); + + /** + * Verify {@code namedDelete(String)} API method with ordered parameters. + */ + void testNamedDeleteOrderArgs(); + + /** + * Verify {@code delete(String)} API method with ordered parameters. + */ + void testDeleteOrderArgs(); + } + + /** + * Test exceptional statements. + */ + interface TxExceptionalStmtTest { + + /** + * Verify that execution of query with non-existing named statement throws an exception. + */ + void testCreateNamedQueryNonExistentStmt(); + + /** + * Verify that execution of query with both named and ordered arguments throws an exception. + */ + void testCreateNamedQueryNamedAndOrderArgsWithoutArgs(); + + /** + * Verify that execution of query with both named and ordered arguments throws an exception. + */ + void testCreateNamedQueryNamedAndOrderArgsWithArgs(); + + /** + * Verify that execution of query with named arguments throws an exception while trying to set ordered argument. + */ + void testCreateNamedQueryNamedArgsSetOrderArg(); + + /** + * Verify that execution of query with ordered arguments throws an exception while trying to set named argument. + */ + void testCreateNamedQueryOrderArgsSetNamedArg(); + } + + /** + * Test set of basic JDBC get calls in transaction. + */ + interface TxGetTest { + + /** + * Verify {@code createNamedGet(String, String)} API method with named parameters. + */ + void testCreateNamedGetStrStrNamedArgs(); + + /** + * Verify {@code createNamedGet(String)} API method with named parameters. + */ + void testCreateNamedGetStrNamedArgs(); + + /** + * Verify {@code createNamedGet(String)} API method with ordered parameters. + */ + void testCreateNamedGetStrOrderArgs(); + + /** + * Verify {@code createGet(String)} API method with named parameters. + */ + void testCreateGetNamedArgs(); + + /** + * Verify {@code createGet(String)} API method with ordered parameters. + */ + void testCreateGetOrderArgs(); + + /** + * Verify {@code namedGet(String)} API method with ordered parameters passed directly to the {@code query} method. + */ + void testNamedGetStrOrderArgs(); + + /** + * Verify {@code get(String)} API method with ordered parameters passed directly to the {@code query} method. + */ + void testGetStrOrderArgs(); + } + + /** + * Test set of basic JDBC inserts in transaction. + */ + interface TxInsertTest { + + /** + * Verify {@code createNamedInsert(String, String)} API method with named parameters. + */ + void testCreateNamedInsertStrStrNamedArgs(); + + /** + * Verify {@code createNamedInsert(String)} API method with named parameters. + */ + void testCreateNamedInsertStrNamedArgs(); + + /** + * Verify {@code createNamedInsert(String)} API method with ordered parameters. + */ + void testCreateNamedInsertStrOrderArgs(); + + /** + * Verify {@code createInsert(String)} API method with named parameters. + */ + void testCreateInsertNamedArgs(); + + /** + * Verify {@code createInsert(String)} API method with ordered parameters. + */ + void testCreateInsertOrderArgs(); + + /** + * Verify {@code namedInsert(String)} API method with ordered parameters passed directly to the {@code insert} method. + */ + void testNamedInsertOrderArgs(); + + /** + * Verify {@code insert(String)} API method with ordered parameters passed directly to the {@code insert} method. + */ + void testInsertOrderArgs(); + } + + /** + * Test set of basic JDBC queries in transaction. + */ + interface TxQueriesTest { + + /** + * Verify {@code createNamedQuery(String, String)} API method with ordered parameters. + */ + void testCreateNamedQueryStrStrOrderArgs(); + + /** + * Verify {@code createNamedQuery(String)} API method with named parameters. + */ + void testCreateNamedQueryStrNamedArgs(); + + /** + * Verify {@code createNamedQuery(String)} API method with ordered parameters. + */ + void testCreateNamedQueryStrOrderArgs(); + + /** + * Verify {@code createQuery(String)} API method with named parameters. + */ + void testCreateQueryNamedArgs(); + + /** + * Verify {@code createQuery(String)} API method with ordered parameters. + */ + void testCreateQueryOrderArgs(); + + /** + * Verify {@code namedQuery(String)} API method with ordered parameters passed directly to the {@code namedQuery} method. + */ + void testNamedQueryOrderArgs(); + + /** + * Verify {@code query(String)} API method with ordered parameters passed directly to the {@code query} method. + */ + void testQueryOrderArgs(); + } + + /** + * Test set of basic JDBC updates in transaction. + */ + interface TxUpdateTest { + + /** + * Verify {@code createNamedUpdate(String, String)} API method with named parameters. + */ + void testCreateNamedUpdateStrStrNamedArgs(); + + /** + * Verify {@code createNamedUpdate(String)} API method with named parameters. + */ + void testCreateNamedUpdateStrNamedArgs(); + + /** + * Verify {@code createNamedUpdate(String)} API method with ordered parameters. + */ + void testCreateNamedUpdateStrOrderArgs(); + + /** + * Verify {@code createUpdate(String)} API method with named parameters. + */ + void testCreateUpdateNamedArgs(); + + /** + * Verify {@code createUpdate(String)} API method with ordered parameters. + */ + void testCreateUpdateOrderArgs(); + + /** + * Verify {@code namedUpdate(String)} API method with named parameters. + */ + void testNamedUpdateNamedArgs(); + + /** + * Verify {@code update(String)} API method with ordered parameters. + */ + void testUpdateOrderArgs(); + } +} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/model/Pokemon.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/model/Pokemon.java index 2305475ddbe..e6fa9b3ec32 100644 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/model/Pokemon.java +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/model/Pokemon.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. + * Copyright (c) 2021, 2024 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. @@ -15,226 +15,25 @@ */ package io.helidon.tests.integration.dbclient.common.model; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.Map; - -import io.helidon.dbclient.DbMapper; -import io.helidon.dbclient.DbRow; - -import jakarta.json.Json; -import jakarta.json.JsonArrayBuilder; -import jakarta.json.JsonObject; -import jakarta.json.JsonObjectBuilder; /** - * {@code Pokemon} POJO. + * {@code Pokemon}. + * + * @param id id + * @param name name + * @param types types */ -@SuppressWarnings("SpellCheckingInspection") -public class Pokemon { +public record Pokemon(int id, String name, List types) { /** - * {@code Pokemon} POJO mapper. + * Create a new instance. + * + * @param id id + * @param name name + * @param types types */ - public static final class PokemonMapper implements DbMapper { - - public static final PokemonMapper INSTANCE = new PokemonMapper(); - - @Override - public Pokemon read(DbRow row) { - return new Pokemon(row.column("id").get(Integer.class), row.column("name").get(String.class)); - } - - @Override - public Map toNamedParameters(Pokemon value) { - Map params = new HashMap<>(2); - params.put("id", value.getId()); - params.put("name", value.getName()); - return params; - } - - @Override - public List toIndexedParameters(Pokemon value) { - List params = new ArrayList<>(2); - params.add(value.getName()); - params.add(value.getId()); - return params; - } - - } - - /** - * Map of {@code Pokemon} by ID. - */ - public static final Map POKEMONS = new HashMap<>(); - - static { - // query tests - POKEMONS.put(1, new Pokemon(1, "Pikachu", Type.TYPES.get(13))); - POKEMONS.put(2, new Pokemon(2, "Raichu", Type.TYPES.get(13))); - POKEMONS.put(3, new Pokemon(3, "Machop", Type.TYPES.get(2))); - POKEMONS.put(4, new Pokemon(4, "Snorlax", Type.TYPES.get(1))); - POKEMONS.put(5, new Pokemon(5, "Charizard", Type.TYPES.get(10), Type.TYPES.get(3))); - POKEMONS.put(6, new Pokemon(6, "Meowth", Type.TYPES.get(1))); - POKEMONS.put(7, new Pokemon(7, "Gyarados", Type.TYPES.get(3), Type.TYPES.get(11))); - // update tests - POKEMONS.put(8, new Pokemon(8, "Spearow", Type.TYPES.get(1), Type.TYPES.get(3))); - POKEMONS.put(9, new Pokemon(9, "Fearow", Type.TYPES.get(1), Type.TYPES.get(3))); - POKEMONS.put(10, new Pokemon(10, "Ekans", Type.TYPES.get(4))); - POKEMONS.put(11, new Pokemon(11, "Arbok", Type.TYPES.get(4))); - POKEMONS.put(12, new Pokemon(12, "Sandshrew", Type.TYPES.get(5))); - POKEMONS.put(13, new Pokemon(13, "Sandslash", Type.TYPES.get(5))); - POKEMONS.put(14, new Pokemon(14, "Diglett", Type.TYPES.get(5))); - // delete tests - POKEMONS.put(15, new Pokemon(15, "Rayquaza", Type.TYPES.get(3), Type.TYPES.get(16))); - POKEMONS.put(16, new Pokemon(16, "Lugia", Type.TYPES.get(3), Type.TYPES.get(14))); - POKEMONS.put(17, new Pokemon(17, "Ho-Oh", Type.TYPES.get(3), Type.TYPES.get(10))); - POKEMONS.put(18, new Pokemon(18, "Raikou", Type.TYPES.get(13))); - POKEMONS.put(19, new Pokemon(19, "Giratina", Type.TYPES.get(8), Type.TYPES.get(16))); - POKEMONS.put(20, new Pokemon(20, "Regirock", Type.TYPES.get(6))); - POKEMONS.put(21, new Pokemon(21, "Kyogre", Type.TYPES.get(11))); - // IDs reserved for insert tests are 22 - 28 - // DML update tests - POKEMONS.put(29, new Pokemon(29, "Piplup", Type.TYPES.get(11))); - POKEMONS.put(30, new Pokemon(30, "Prinplup", Type.TYPES.get(11))); - POKEMONS.put(31, new Pokemon(31, "Empoleon", Type.TYPES.get(9), Type.TYPES.get(11))); - POKEMONS.put(32, new Pokemon(32, "Staryu", Type.TYPES.get(11))); - POKEMONS.put(33, new Pokemon(33, "Starmie", Type.TYPES.get(11), Type.TYPES.get(14))); - POKEMONS.put(34, new Pokemon(34, "Horsea", Type.TYPES.get(11))); - POKEMONS.put(35, new Pokemon(35, "Seadra", Type.TYPES.get(11))); - // DML delete tests - POKEMONS.put(36, new Pokemon(36, "Mudkip", Type.TYPES.get(11))); - POKEMONS.put(37, new Pokemon(37, "Marshtomp", Type.TYPES.get(5), Type.TYPES.get(11))); - POKEMONS.put(38, new Pokemon(38, "Swampert", Type.TYPES.get(5), Type.TYPES.get(11))); - POKEMONS.put(39, new Pokemon(39, "Muk", Type.TYPES.get(4))); - POKEMONS.put(40, new Pokemon(40, "Grimer", Type.TYPES.get(4))); - POKEMONS.put(41, new Pokemon(41, "Cubchoo", Type.TYPES.get(15))); - POKEMONS.put(42, new Pokemon(42, "Beartic", Type.TYPES.get(15))); - // IDs reserved for DML insert tests are 43 - 49 - // DML statement IT - POKEMONS.put(50, new Pokemon(50, "Shinx", Type.TYPES.get(13))); - POKEMONS.put(51, new Pokemon(51, "Luxio", Type.TYPES.get(13))); - POKEMONS.put(52, new Pokemon(52, "Luxray", Type.TYPES.get(13))); - POKEMONS.put(53, new Pokemon(53, "Kricketot", Type.TYPES.get(7))); - POKEMONS.put(54, new Pokemon(54, "Kricketune", Type.TYPES.get(7))); - POKEMONS.put(55, new Pokemon(55, "Phione", Type.TYPES.get(11))); - POKEMONS.put(56, new Pokemon(56, "Chatot", Type.TYPES.get(1), Type.TYPES.get(3))); - // update tests in transaction - POKEMONS.put(57, new Pokemon(57, "Teddiursa", Type.TYPES.get(1))); - POKEMONS.put(58, new Pokemon(58, "Ursaring", Type.TYPES.get(1))); - POKEMONS.put(59, new Pokemon(59, "Slugma", Type.TYPES.get(10))); - POKEMONS.put(60, new Pokemon(60, "Magcargo", Type.TYPES.get(6), Type.TYPES.get(10))); - POKEMONS.put(61, new Pokemon(61, "Lotad", Type.TYPES.get(11), Type.TYPES.get(12))); - POKEMONS.put(62, new Pokemon(62, "Lombre", Type.TYPES.get(11), Type.TYPES.get(12))); - POKEMONS.put(63, new Pokemon(63, "Ludicolo", Type.TYPES.get(11), Type.TYPES.get(12))); - // DML update tests in transaction - POKEMONS.put(64, new Pokemon(64, "Natu", Type.TYPES.get(3), Type.TYPES.get(14))); - POKEMONS.put(65, new Pokemon(65, "Xatu", Type.TYPES.get(3), Type.TYPES.get(14))); - POKEMONS.put(66, new Pokemon(66, "Snubbull", Type.TYPES.get(18))); - POKEMONS.put(67, new Pokemon(67, "Granbull", Type.TYPES.get(18))); - POKEMONS.put(68, new Pokemon(68, "Entei", Type.TYPES.get(10))); - POKEMONS.put(69, new Pokemon(69, "Raikou", Type.TYPES.get(13))); - POKEMONS.put(70, new Pokemon(70, "Suicune", Type.TYPES.get(11))); - // delete tests in transaction - POKEMONS.put(71, new Pokemon(71, "Omanyte", Type.TYPES.get(6), Type.TYPES.get(11))); - POKEMONS.put(72, new Pokemon(72, "Omastar", Type.TYPES.get(6), Type.TYPES.get(11))); - POKEMONS.put(73, new Pokemon(73, "Kabuto", Type.TYPES.get(6), Type.TYPES.get(11))); - POKEMONS.put(74, new Pokemon(74, "Kabutops", Type.TYPES.get(6), Type.TYPES.get(11))); - POKEMONS.put(75, new Pokemon(75, "Chikorita", Type.TYPES.get(12))); - POKEMONS.put(76, new Pokemon(76, "Bayleef", Type.TYPES.get(12))); - POKEMONS.put(77, new Pokemon(77, "Meganium", Type.TYPES.get(12))); - // DML delete tests in transaction - POKEMONS.put(78, new Pokemon(78, "Trapinch", Type.TYPES.get(5))); - POKEMONS.put(79, new Pokemon(79, "Vibrava", Type.TYPES.get(5), Type.TYPES.get(16))); - POKEMONS.put(80, new Pokemon(80, "Spoink", Type.TYPES.get(14))); - POKEMONS.put(81, new Pokemon(81, "Grumpig", Type.TYPES.get(14))); - POKEMONS.put(82, new Pokemon(82, "Beldum", Type.TYPES.get(9), Type.TYPES.get(14))); - POKEMONS.put(83, new Pokemon(83, "Metang", Type.TYPES.get(9), Type.TYPES.get(14))); - POKEMONS.put(84, new Pokemon(84, "Metagross", Type.TYPES.get(9), Type.TYPES.get(14))); - // IDs reserved for DML insert tests in transaction are 85 - 98 - // mapping tests - POKEMONS.put(99, new Pokemon(99, "Moltres", Type.TYPES.get(3), Type.TYPES.get(10))); - POKEMONS.put(100, new Pokemon(100, "Masquerain", Type.TYPES.get(3), Type.TYPES.get(7))); - POKEMONS.put(101, new Pokemon(101, "Makuhita", Type.TYPES.get(2))); - POKEMONS.put(102, new Pokemon(102, "Hariyama", Type.TYPES.get(2))); - // IDs reserved for mapping tests with insert are 103 - 104 - } - - public static List typesList(Type... types) { - if (types == null) { - return null; - } - List typesList = new ArrayList<>(types.length); - typesList.addAll(Arrays.asList(types)); - return typesList; - } - - private final int id; - private final String name; - private final List types; - public Pokemon(int id, String name, Type... types) { - this.id = id; - this.name = name; - this.types = new ArrayList<>(types != null ? types.length : 0); - if (types != null) { - this.types.addAll(Arrays.asList(types)); - } - } - - public Pokemon(int id, String name, List types) { - this.id = id; - this.name = name; - this.types = types != null ? types : List.of(); - } - - public int getId() { - return id; - } - - public String getName() { - return name; - } - - public List getTypes() { - return types; - } - - public Type[] getTypesArray() { - return types.toArray(new Type[0]); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("Pokemon: {id="); - sb.append(id); - sb.append(", name="); - sb.append(name); - sb.append(", types=["); - boolean first = true; - for (Type type : types) { - if (first) { - first = false; - } else { - sb.append(", "); - } - sb.append(type.toString()); - } - sb.append("]}"); - return sb.toString(); - } - - public JsonObject toJsonObject() { - JsonObjectBuilder job = Json.createObjectBuilder(); - job.add("id", id); - job.add("name", name); - JsonArrayBuilder typesArray = Json.createArrayBuilder(); - types.forEach(type -> typesArray.add(type.toJsonObject())); - job.add("types", typesArray.build()); - return job.build(); + this(id, name, List.of(types)); } - } diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/model/Pokemons.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/model/Pokemons.java new file mode 100644 index 00000000000..218af74d1ff --- /dev/null +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/model/Pokemons.java @@ -0,0 +1,405 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.common.model; + +import java.util.List; + +/** + * {@code Pokemon} data set. + */ +@SuppressWarnings("SpellCheckingInspection") +public final class Pokemons { + + private Pokemons() { + // cannot be instantiated + } + + /** + * {@code Pikachu}. + */ + public static final Pokemon PIKACHU = new Pokemon(1, "Pikachu", Types.ELECTRIC); + + /** + * {@code Raichu}. + */ + public static final Pokemon RAICHU = new Pokemon(2, "Raichu", Types.ELECTRIC); + + /** + * {@code Machop}. + */ + public static final Pokemon MACHOP = new Pokemon(3, "Machop", Types.FIGHTING); + + /** + * {@code Snorlax}. + */ + public static final Pokemon SNORLAX = new Pokemon(4, "Snorlax", Types.NORMAL); + + /** + * {@code Charizard}. + */ + public static final Pokemon CHARIZARD = new Pokemon(5, "Charizard", Types.FIRE, Types.FLYING); + + /** + * {@code Meowth}. + */ + public static final Pokemon MEOWTH = new Pokemon(6, "Meowth", Types.NORMAL); + + /** + * {@code Gyarados}. + */ + public static final Pokemon GYARADOS = new Pokemon(7, "Gyarados", Types.FLYING, Types.WATER); + + /** + * {@code Spearow}. + */ + public static final Pokemon SPEAROW = new Pokemon(8, "Spearow", Types.NORMAL, Types.FLYING); + + /** + * {@code Fearow}. + */ + public static final Pokemon FEAROW = new Pokemon(9, "Fearow", Types.NORMAL, Types.FLYING); + + /** + * {@code Ekans}. + */ + public static final Pokemon EKANS = new Pokemon(10, "Ekans", Types.POISON); + + /** + * {@code Arbok}. + */ + public static final Pokemon ARBOK = new Pokemon(11, "Arbok", Types.POISON); + + /** + * {@code Sandshrew}. + */ + public static final Pokemon SANDSHREW = new Pokemon(12, "Sandshrew", Types.GROUND); + + /** + * {@code Sandslash}. + */ + public static final Pokemon SANDSLASH = new Pokemon(13, "Sandslash", Types.GROUND); + + /** + * {@code Diglett}. + */ + public static final Pokemon DIGLETT = new Pokemon(14, "Diglett", Types.GROUND); + + /** + * {@code Rayquaza}. + */ + public static final Pokemon RAYQUAZA = new Pokemon(15, "Rayquaza", Types.FLYING, Types.DRAGON); + + /** + * {@code Lugia}. + */ + public static final Pokemon LUGIA = new Pokemon(16, "Lugia", Types.FLYING, Types.PSYCHIC); + + /** + * {@code Ho-Oh}. + */ + public static final Pokemon HOOH = new Pokemon(17, "Ho-Oh", Types.FLYING, Types.FIRE); + + /** + * {@code Raikou}. + */ + public static final Pokemon RAIKOU = new Pokemon(18, "Raikou", Types.ELECTRIC); + + /** + * {@code Giratina}. + */ + public static final Pokemon GIRATINA = new Pokemon(19, "Giratina", Types.GHOST, Types.DRAGON); + + /** + * {@code Regirock}. + */ + public static final Pokemon REGIROCK = new Pokemon(20, "Regirock", Types.ROCK); + + /** + * {@code Kyogre}. + */ + public static final Pokemon KYOGRE = new Pokemon(21, "Kyogre", Types.WATER); + + /** + * {@code Piplup}. + */ + public static final Pokemon PIPLUP = new Pokemon(29, "Piplup", Types.WATER); + + /** + * {@code Prinplup}. + */ + public static final Pokemon PRINPLUP = new Pokemon(30, "Prinplup", Types.WATER); + + /** + * {@code Empoleon}. + */ + public static final Pokemon EMPOLEON = new Pokemon(31, "Empoleon", Types.STEEL, Types.WATER); + + /** + * {@code Staryu}. + */ + public static final Pokemon STARYU = new Pokemon(32, "Staryu", Types.WATER); + + /** + * {@code Starmie}. + */ + public static final Pokemon STARMIE = new Pokemon(33, "Starmie", Types.WATER, Types.PSYCHIC); + + /** + * {@code Horsea}. + */ + public static final Pokemon HORSEA = new Pokemon(34, "Horsea", Types.WATER); + + /** + * {@code Seadra}. + */ + public static final Pokemon SEADRA = new Pokemon(35, "Seadra", Types.WATER); + + /** + * {@code Mudkip}. + */ + public static final Pokemon MUDKIP = new Pokemon(36, "Mudkip", Types.WATER); + + /** + * {@code Marshtomp}. + */ + public static final Pokemon MARSHTOMP = new Pokemon(37, "Marshtomp", Types.GROUND, Types.WATER); + + /** + * {@code Swampert}. + */ + public static final Pokemon SWAMPERT = new Pokemon(38, "Swampert", Types.GROUND, Types.WATER); + + /** + * {@code Muk}. + */ + public static final Pokemon MUK = new Pokemon(39, "Muk", Types.POISON); + + /** + * {@code Grimer}. + */ + public static final Pokemon GRIMER = new Pokemon(40, "Grimer", Types.POISON); + + /** + * {@code Cubchoo}. + */ + public static final Pokemon CUBCHOO = new Pokemon(41, "Cubchoo", Types.ICE); + + /** + * {@code Beartic}. + */ + public static final Pokemon BEARTIC = new Pokemon(42, "Beartic", Types.ICE); + + /** + * {@code Shinx}. + */ + public static final Pokemon SHINX = new Pokemon(50, "Shinx", Types.ELECTRIC); + + /** + * {@code Luxio}. + */ + public static final Pokemon LUXIO = new Pokemon(51, "Luxio", Types.ELECTRIC); + + /** + * {@code Luxray}. + */ + public static final Pokemon LUXRAY = new Pokemon(52, "Luxray", Types.ELECTRIC); + + /** + * {@code Kricketot}. + */ + public static final Pokemon KRICKETOT = new Pokemon(53, "Kricketot", Types.GHOST); + + /** + * {@code Kricketune}. + */ + public static final Pokemon KRICKETUNE = new Pokemon(54, "Kricketune", Types.GHOST); + + /** + * {@code Phione}. + */ + public static final Pokemon PHIONE = new Pokemon(55, "Phione", Types.WATER); + + /** + * {@code Chatot}. + */ + public static final Pokemon CHATOT = new Pokemon(56, "Chatot", Types.NORMAL, Types.FLYING); + + /** + * {@code Teddiursa}. + */ + public static final Pokemon TEDDIURSA = new Pokemon(57, "Teddiursa", Types.NORMAL); + + /** + * {@code Ursaring}. + */ + public static final Pokemon URSARING = new Pokemon(58, "Ursaring", Types.NORMAL); + + /** + * {@code Slugma}. + */ + public static final Pokemon SLUGMA = new Pokemon(59, "Slugma", Types.FIRE); + + /** + * {@code Magcargo}. + */ + public static final Pokemon MAGCARGO = new Pokemon(60, "Magcargo", Types.ROCK, Types.FIRE); + + /** + * {@code Lotad}. + */ + public static final Pokemon LOTAD = new Pokemon(61, "Lotad", Types.WATER, Types.GRASS); + + /** + * {@code Lombre}. + */ + public static final Pokemon LOMBRE = new Pokemon(62, "Lombre", Types.WATER, Types.GRASS); + + /** + * {@code Ludicolo}. + */ + public static final Pokemon LUDICOLO = new Pokemon(63, "Ludicolo", Types.WATER, Types.GRASS); + + /** + * {@code Natu}. + */ + public static final Pokemon NATU = new Pokemon(64, "Natu", Types.FLYING, Types.PSYCHIC); + + /** + * {@code Xatu}. + */ + public static final Pokemon XATU = new Pokemon(65, "Xatu", Types.FLYING, Types.PSYCHIC); + + /** + * {@code Snubbull}. + */ + public static final Pokemon SNUBBULL = new Pokemon(66, "Snubbull", Types.FAIRY); + + /** + * {@code Granbull}. + */ + public static final Pokemon GRANBULL = new Pokemon(67, "Granbull", Types.FAIRY); + + /** + * {@code Entei}. + */ + public static final Pokemon ENTEI = new Pokemon(68, "Entei", Types.FIRE); + + /** + * {@code Suicune}. + */ + public static final Pokemon SUICUNE = new Pokemon(70, "Suicune", Types.WATER); + + /** + * {@code Omanyte}. + */ + public static final Pokemon OMANYTE = new Pokemon(71, "Omanyte", Types.ROCK, Types.WATER); + + /** + * {@code Omastar}. + */ + public static final Pokemon OMASTAR = new Pokemon(72, "Omastar", Types.ROCK, Types.WATER); + + /** + * {@code Kabuto}. + */ + public static final Pokemon KABUTO = new Pokemon(73, "Kabuto", Types.ROCK, Types.WATER); + + /** + * {@code Kabutops}. + */ + public static final Pokemon KABUTOPS = new Pokemon(74, "Kabutops", Types.ROCK, Types.WATER); + + /** + * {@code Chikorita}. + */ + public static final Pokemon CHIKORITA = new Pokemon(75, "Chikorita", Types.GRASS); + + /** + * {@code Bayleef}. + */ + public static final Pokemon BAYLEEF = new Pokemon(76, "Bayleef", Types.GRASS); + + /** + * {@code Meganium}. + */ + public static final Pokemon MEGANIUM = new Pokemon(77, "Meganium", Types.GRASS); + + /** + * {@code Trapinch}. + */ + public static final Pokemon TRAPINCH = new Pokemon(78, "Trapinch", Types.GROUND); + + /** + * {@code Vibrava}. + */ + public static final Pokemon VIBRAVA = new Pokemon(79, "Vibrava", Types.GROUND, Types.DRAGON); + + /** + * {@code Spoink}. + */ + public static final Pokemon SPOINK = new Pokemon(80, "Spoink", Types.PSYCHIC); + + /** + * {@code Grumpig}. + */ + public static final Pokemon GRUMPIG = new Pokemon(81, "Grumpig", Types.PSYCHIC); + + /** + * {@code Beldum}. + */ + public static final Pokemon BELDUM = new Pokemon(82, "Beldum", Types.STEEL, Types.PSYCHIC); + + /** + * {@code Metang}. + */ + public static final Pokemon METANG = new Pokemon(83, "Metang", Types.STEEL, Types.PSYCHIC); + + /** + * {@code Metagross}. + */ + public static final Pokemon METAGROSS = new Pokemon(84, "Metagross", Types.STEEL, Types.PSYCHIC); + + /** + * {@code Moltres}. + */ + public static final Pokemon MOLTRES = new Pokemon(99, "Moltres", Types.FLYING, Types.FIRE); + + /** + * {@code Masquerain}. + */ + public static final Pokemon MASQUERAIN = new Pokemon(100, "Masquerain", Types.FLYING, Types.GHOST); + + /** + * {@code Makuhita}. + */ + public static final Pokemon MAKUHITA = new Pokemon(101, "Makuhita", Types.FIGHTING); + + /** + * {@code Hariyama}. + */ + public static final Pokemon HARIYAMA = new Pokemon(102, "Hariyama", Types.FIGHTING); + + /** + * All {@code pokemons}. + */ + public static final List ALL = List.of( + PIKACHU, RAICHU, MACHOP, SNORLAX, CHARIZARD, MEOWTH, GYARADOS, SPEAROW, FEAROW, EKANS, ARBOK, SANDSHREW, SANDSLASH, + DIGLETT, RAYQUAZA, LUGIA, HOOH, RAIKOU, GIRATINA, REGIROCK, KYOGRE, PIPLUP, PRINPLUP, EMPOLEON, STARYU, STARMIE, + HORSEA, SEADRA, MUDKIP, MARSHTOMP, SWAMPERT, MUK, GRIMER, CUBCHOO, BEARTIC, SHINX, LUXIO, LUXRAY, KRICKETOT, + KRICKETUNE, PHIONE, CHATOT, TEDDIURSA, URSARING, SLUGMA, MAGCARGO, LOTAD, LOMBRE, LUDICOLO, NATU, XATU, SNUBBULL, + GRANBULL, ENTEI, SUICUNE, OMANYTE, OMASTAR, KABUTO, KABUTOPS, CHIKORITA, BAYLEEF, MEGANIUM, TRAPINCH, VIBRAVA, + SPOINK, GRUMPIG, BELDUM, METANG, METAGROSS, MOLTRES, MASQUERAIN, MAKUHITA, HARIYAMA); +} diff --git a/tests/integration/harness/src/main/java/module-info.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/model/Range.java similarity index 53% rename from tests/integration/harness/src/main/java/module-info.java rename to tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/model/Range.java index 298fa495e84..10cb03e1970 100644 --- a/tests/integration/harness/src/main/java/module-info.java +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/model/Range.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2021, 2024 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. @@ -13,23 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package io.helidon.tests.integration.dbclient.common.model; /** - * Helidon Tests Integration Harness. + * Range. + * + * @param idMin beginning of range. + * @param idMax end of range. */ -module io.helidon.tests.integration.harness { - - requires jakarta.json; - - requires org.junit.platform.suite.api; - requires org.junit.jupiter.api; - requires org.junit.platform.engine; - requires org.junit.platform.launcher; - - requires io.helidon.common.media.type; - requires io.helidon.http.media.jsonp; - requires io.helidon.webclient.http1; - - exports io.helidon.tests.integration.harness; - +public record Range(int idMin, int idMax) { } diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/model/RangePoJo.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/model/RangePoJo.java deleted file mode 100644 index 74d98b15dad..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/model/RangePoJo.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.dbclient.common.model; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import io.helidon.dbclient.DbMapper; -import io.helidon.dbclient.DbRow; - -/** - * POJO used to define {@code Pokemon} IDs range in query statement tests. - * - * @param idMin Beginning of IDs range. - * @param idMax End of IDs range. - */ -public record RangePoJo(int idMin, int idMax) { - - public static final class Mapper implements DbMapper { - - public static final Mapper INSTANCE = new Mapper(); - - @Override - public RangePoJo read(DbRow row) { - throw new UnsupportedOperationException("Read operation is not implemented."); - } - - @Override - public Map toNamedParameters(RangePoJo value) { - Map params = new HashMap<>(2); - params.put("idmin", value.idMin()); - params.put("idmax", value.idMax()); - return params; - } - - @Override - public List toIndexedParameters(RangePoJo value) { - List params = new ArrayList<>(2); - params.add(value.idMin()); - params.add(value.idMax()); - return params; - } - - } - - /** - * Creates an instance of Range POJO. - * - * @param idMin beginning of IDs range - * @param idMax end of IDs range - */ - public RangePoJo { - } - - /** - * Get beginning of IDs range. - * - * @return beginning of IDs range - */ - @Override - public int idMin() { - return idMin; - } - - /** - * Get end of IDs range. - * - * @return end of IDs range - */ - @Override - public int idMax() { - return idMax; - } - -} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/model/Type.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/model/Type.java index 45b938455c1..066aabf4cc5 100644 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/model/Type.java +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/model/Type.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023 Oracle and/or its affiliates. + * Copyright (c) 2021, 2024 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. @@ -15,53 +15,11 @@ */ package io.helidon.tests.integration.dbclient.common.model; -import java.util.HashMap; -import java.util.Map; - -import jakarta.json.Json; -import jakarta.json.JsonObject; -import jakarta.json.JsonObjectBuilder; - /** - * {@code Pokemon} type POJO. + * {@code Pokemon}. + * + * @param id id + * @param name name */ public record Type(int id, String name) { - - /** - * Map of {@code Pokemon} types by ID. - */ - public static final Map TYPES = new HashMap<>(); - - static { - TYPES.put(1, new Type(1, "Normal")); - TYPES.put(2, new Type(2, "Fighting")); - TYPES.put(3, new Type(3, "Flying")); - TYPES.put(4, new Type(4, "Poison")); - TYPES.put(5, new Type(5, "Ground")); - TYPES.put(6, new Type(6, "Rock")); - TYPES.put(7, new Type(7, "Bug")); - TYPES.put(8, new Type(8, "Ghost")); - TYPES.put(9, new Type(9, "Steel")); - TYPES.put(10, new Type(10, "Fire")); - TYPES.put(11, new Type(11, "Water")); - TYPES.put(12, new Type(12, "Grass")); - TYPES.put(13, new Type(13, "Electric")); - TYPES.put(14, new Type(14, "Psychic")); - TYPES.put(15, new Type(15, "Ice")); - TYPES.put(16, new Type(16, "Dragon")); - TYPES.put(17, new Type(17, "Dark")); - TYPES.put(18, new Type(18, "Fairy")); - } - - @Override - public String toString() { - return "Type: {id=" + id + ", name=" + name + "}"; - } - - public JsonObject toJsonObject() { - final JsonObjectBuilder job = Json.createObjectBuilder(); - job.add("id", id); - job.add("name", name); - return job.build(); - } } diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/model/Types.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/model/Types.java new file mode 100644 index 00000000000..3fa6415703a --- /dev/null +++ b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/model/Types.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.common.model; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * {@code type} data set. + */ +public final class Types { + + private Types() { + // cannot be instantiated + } + + /** + * Map of {@code Pokemon} types by ID. + */ + public static final Map TYPES = new HashMap<>(); + + /** + * {@code Normal}. + */ + public static final Type NORMAL = new Type(1, "Normal"); + + /** + * {@code Fighting}. + */ + public static final Type FIGHTING = new Type(2, "Fighting"); + + /** + * {@code Flying}. + */ + public static final Type FLYING = new Type(3, "Flying"); + + /** + * {@code Poison}. + */ + public static final Type POISON = new Type(4, "Poison"); + + /** + * {@code Ground}. + */ + public static final Type GROUND = new Type(5, "Ground"); + + /** + * {@code Rock}. + */ + public static final Type ROCK = new Type(6, "Rock"); + + /** + * {@code Bug}. + */ + public static final Type BUG = new Type(7, "Bug"); + + /** + * {@code Ghost}. + */ + public static final Type GHOST = new Type(8, "Ghost"); + + /** + * {@code Steel}. + */ + public static final Type STEEL = new Type(9, "Steel"); + + /** + * {@code Fire}. + */ + public static final Type FIRE = new Type(10, "Fire"); + + /** + * {@code Water}. + */ + public static final Type WATER = new Type(11, "Water"); + + /** + * {@code Grass}. + */ + public static final Type GRASS = new Type(12, "Grass"); + + /** + * {@code Electric}. + */ + public static final Type ELECTRIC = new Type(13, "Electric"); + + /** + * {@code Psychic}. + */ + public static final Type PSYCHIC = new Type(14, "Psychic"); + + /** + * {@code Ice}. + */ + public static final Type ICE = new Type(15, "Ice"); + + /** + * {@code Dragon}. + */ + public static final Type DRAGON = new Type(16, "Dragon"); + + /** + * {@code Dark}. + */ + public static final Type DARK = new Type(17, "Dark"); + + /** + * {@code Fairy}. + */ + public static final Type FAIRY = new Type(18, "Fairy"); + + /** + * All types. + */ + public static final List ALL = List.of(NORMAL, FIGHTING, FLYING, POISON, GROUND, ROCK, BUG, GHOST, STEEL, FIRE, WATER, + GRASS, ELECTRIC, PSYCHIC, ICE, DRAGON, DARK, FAIRY); + + static { + Types.TYPES.put(1, Types.NORMAL); + Types.TYPES.put(2, Types.FIGHTING); + Types.TYPES.put(3, Types.FLYING); + Types.TYPES.put(4, Types.POISON); + Types.TYPES.put(5, Types.GROUND); + Types.TYPES.put(6, Types.ROCK); + Types.TYPES.put(7, Types.BUG); + Types.TYPES.put(8, Types.GHOST); + Types.TYPES.put(9, Types.STEEL); + Types.TYPES.put(10, Types.FIRE); + Types.TYPES.put(11, Types.WATER); + Types.TYPES.put(12, Types.GRASS); + Types.TYPES.put(13, Types.ELECTRIC); + Types.TYPES.put(14, Types.PSYCHIC); + Types.TYPES.put(15, Types.ICE); + Types.TYPES.put(16, Types.DRAGON); + Types.TYPES.put(17, Types.DARK); + Types.TYPES.put(18, Types.FAIRY); + } +} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/DbClientParameterResolver.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/DbClientParameterResolver.java deleted file mode 100644 index 59004a87b0d..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/DbClientParameterResolver.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2023 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.tests.integration.dbclient.common.tests; - -import java.util.List; -import java.util.ServiceLoader; - -import io.helidon.common.HelidonServiceLoader; -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; -import io.helidon.tests.integration.dbclient.common.spi.SetupProvider; - -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.api.extension.ParameterContext; -import org.junit.jupiter.api.extension.ParameterResolutionException; -import org.junit.jupiter.api.extension.ParameterResolver; - -public class DbClientParameterResolver implements ParameterResolver { - - private static final SetupProvider SETUP_PROVIDER = initSetupProvider(); - - private static SetupProvider initSetupProvider() { - ServiceLoader loader = ServiceLoader.load(SetupProvider.class); - List providers = HelidonServiceLoader - .builder(loader) - .build() - .asList(); - switch (providers.size()) { - case 0: throw new IllegalStateException("No SetupProvider instance found on the classpath"); - case 1: return providers.getFirst(); - default: throw new IllegalStateException("Multiple SetupProvider instances found on the classpath"); - } - } - - @Override - public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) - throws ParameterResolutionException { - Class type = parameterContext.getParameter().getType(); - if (DbClient.class.isAssignableFrom(type)) { - return true; - } - if (Config.class.isAssignableFrom(type)) { - return true; - } - return false; - } - - @Override - public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) - throws ParameterResolutionException { - Class type = parameterContext.getParameter().getType(); - if (DbClient.class.isAssignableFrom(type)) { - return SETUP_PROVIDER.dbClient(); - } - if (Config.class.isAssignableFrom(type)) { - return SETUP_PROVIDER.config(); - } - return null; - } -} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/ExceptionalStmtIT.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/ExceptionalStmtIT.java deleted file mode 100644 index dfc5ac3ddd6..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/ExceptionalStmtIT.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.tests.integration.dbclient.common.tests; - -import java.lang.System.Logger.Level; - -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbClientException; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import static io.helidon.tests.integration.dbclient.common.model.Pokemon.POKEMONS; -import static org.junit.jupiter.api.Assertions.fail; - -/** - * Test exceptional states. - */ -@ExtendWith(DbClientParameterResolver.class) -class ExceptionalStmtIT { - - private static final System.Logger LOGGER = System.getLogger(ExceptionalStmtIT.class.getName()); - - private final DbClient dbClient; - - ExceptionalStmtIT(DbClient dbClient) { - this.dbClient = dbClient; - } - - /** - * Verify that execution of query with non-existing named statement throws an exception. - */ - @Test - void testCreateNamedQueryNonExistentStmt() { - try { - dbClient.execute() - .createNamedQuery("select-pokemons-not-exists") - .execute() - .forEach(it -> {}); - fail("Execution of non existing statement shall cause an exception to be thrown."); - } catch (DbClientException ex) { - LOGGER.log(Level.DEBUG, () -> String.format("Expected exception: %s", ex.getMessage()), ex); - } - } - - /** - * Verify that execution of query with both named and ordered arguments throws an exception. - */ - @Test - void testCreateNamedQueryNamedAndOrderArgsWithoutArgs() { - try { - dbClient.execute() - .createNamedQuery("select-pokemons-error-arg") - .execute() - .forEach(it -> {}); - fail("Execution of query with both named and ordered parameters without passing any shall fail."); - } catch (DbClientException ex) { - LOGGER.log(Level.DEBUG, () -> String.format("Expected exception: %s", ex.getMessage()), ex); - } - } - - /** - * Verify that execution of query with both named and ordered arguments throws an exception. - */ - @Test - void testCreateNamedQueryNamedAndOrderArgsWithArgs() { - try { - dbClient.execute() - .createNamedQuery("select-pokemons-error-arg") - .addParam("id", POKEMONS.get(5).getId()) - .addParam(POKEMONS.get(5).getName()) - .execute() - .forEach(it -> {}); - fail("Execution of query with both named and ordered parameters without passing them shall fail."); - } catch (DbClientException ex) { - LOGGER.log(Level.DEBUG, () -> String.format("Expected exception: %s", ex.getMessage()), ex); - } - } - - /** - * Verify that execution of query with named arguments throws an exception while trying to set ordered argument. - */ - @Test - void testCreateNamedQueryNamedArgsSetOrderArg() { - try { - dbClient.execute() - .createNamedQuery("select-pokemon-named-arg") - .addParam(POKEMONS.get(5).getName()) - .execute() - .forEach(it -> {}); - fail("Execution of query with named parameter with passing ordered parameter value shall fail."); - } catch (DbClientException ex) { - LOGGER.log(Level.DEBUG, () -> String.format("Expected exception: %s", ex.getMessage()), ex); - } - } - - /** - * Verify that execution of query with ordered arguments throws an exception while trying to set named argument. - */ - @Test - void testCreateNamedQueryOrderArgsSetNamedArg() { - try { - dbClient.execute() - .createNamedQuery("select-pokemon-order-arg") - .addParam("name", POKEMONS.get(6).getName()) - .execute() - .forEach(it -> {}); - fail("Execution of query with ordered parameter with passing named parameter value shall fail."); - } catch (DbClientException ex) { - LOGGER.log(Level.DEBUG, () -> String.format("Expected exception: %s", ex.getMessage()), ex); - } - } -} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/FlowControlIT.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/FlowControlIT.java deleted file mode 100644 index 06e18eb0f4e..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/FlowControlIT.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.tests.integration.dbclient.common.tests; - -import java.lang.System.Logger.Level; -import java.util.List; -import java.util.stream.Stream; - -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbRow; -import io.helidon.tests.integration.dbclient.common.model.Type; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import static io.helidon.tests.integration.dbclient.common.model.Type.TYPES; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.empty; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.notNullValue; - -/** - * Verify proper flow control handling in query processing. - */ -@ExtendWith(DbClientParameterResolver.class) -public class FlowControlIT { - - private static final System.Logger LOGGER = System.getLogger(FlowControlIT.class.getName()); - - private final DbClient dbClient; - - FlowControlIT(DbClient dbClient) { - this.dbClient = dbClient; - } - - /** - * Source data verification. - */ - @Test - public void testSourceData() { - Stream rows = dbClient.execute() - .namedQuery("select-types"); - assertThat(rows, notNullValue()); - List list = rows.toList(); - assertThat(list, not(empty())); - assertThat(list.size(), equalTo(18)); - for (DbRow row : list) { - Integer id = row.column(1).get(Integer.class); - String name = row.column(2).get(String.class); - Type type = new Type(id, name); - assertThat(name, TYPES.get(id).name().equals(name)); - LOGGER.log(Level.DEBUG, () -> String.format("Type: %s", type)); - } - } -} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/GetStatementIT.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/GetStatementIT.java deleted file mode 100644 index 0d4a7bc24a2..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/GetStatementIT.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.tests.integration.dbclient.common.tests; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbRow; -import io.helidon.tests.integration.dbclient.common.utils.RangePoJo; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import static io.helidon.tests.integration.dbclient.common.utils.VerifyData.verifyPokemonsIdRange; - -/** - * Test DbStatementGet methods. - */ -@ExtendWith(DbClientParameterResolver.class) -public class GetStatementIT { - - private final DbClient dbClient; - - GetStatementIT(DbClient dbClient) { - this.dbClient = dbClient; - } - - /** - * Verify {@code params(Object... parameters)} parameters setting method. - */ - @Test - public void testGetArrayParams() { - Optional maybeRow = dbClient.execute() - .createNamedGet("select-pokemons-idrng-order-arg") - .params(1, 3) - .execute(); - verifyPokemonsIdRange(maybeRow, 1, 3); - } - - /** - * Verify {@code params(List)} parameters setting method. - */ - @Test - public void testGetListParams() { - List params = new ArrayList<>(2); - params.add(2); - params.add(4); - Optional maybeRow = dbClient.execute() - .createNamedGet("select-pokemons-idrng-order-arg") - .params(params) - .execute(); - - verifyPokemonsIdRange(maybeRow, 2, 4); - } - - /** - * Verify {@code params(Map)} parameters setting method. - */ - @Test - public void testGetMapParams() { - Map params = new HashMap<>(2); - params.put("idmin", 3); - params.put("idmax", 5); - Optional maybeRow = dbClient.execute() - .createNamedGet("select-pokemons-idrng-named-arg") - .params(params) - .execute(); - - verifyPokemonsIdRange(maybeRow, 3, 5); - } - - /** - * Verify {@code addParam(Object parameter)} parameters setting method. - */ - @Test - public void testGetOrderParam() { - Optional maybeRow = dbClient.execute() - .createNamedGet("select-pokemons-idrng-order-arg") - .addParam(4) - .addParam(6) - .execute(); - verifyPokemonsIdRange(maybeRow, 4, 6); - } - - /** - * Verify {@code addParam(String name, Object parameter)} parameters setting method. - */ - @Test - public void testGetNamedParam() { - Optional maybeRow = dbClient.execute() - .createNamedGet("select-pokemons-idrng-named-arg") - .addParam("idmin", 5) - .addParam("idmax", 7) - .execute(); - verifyPokemonsIdRange(maybeRow, 5, 7); - } - - /** - * Verify {@code namedParam(Object parameters)} mapped parameters setting method. - */ - @Test - public void testGetMappedNamedParam() { - RangePoJo range = new RangePoJo(0, 2); - Optional maybeRow = dbClient.execute() - .createNamedGet("select-pokemons-idrng-named-arg") - .namedParam(range) - .execute(); - verifyPokemonsIdRange(maybeRow, 0, 2); - } - - /** - * Verify {@code indexedParam(Object parameters)} mapped parameters setting method. - */ - @Test - public void testGetMappedOrderParam() { - RangePoJo range = new RangePoJo(6, 8); - Optional maybeRow = dbClient.execute() - .createNamedGet("select-pokemons-idrng-order-arg") - .indexedParam(range) - .execute(); - verifyPokemonsIdRange(maybeRow, 6, 8); - } - -} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/HealthCheckIT.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/HealthCheckIT.java deleted file mode 100644 index a3fc9eea2ca..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/HealthCheckIT.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.tests.integration.dbclient.common.tests; - -import java.lang.System.Logger.Level; - -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.health.DbClientHealthCheck; -import io.helidon.health.HealthCheck; -import io.helidon.health.HealthCheckResponse; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - -/** - * Verify that health check works. - */ -@ExtendWith(DbClientParameterResolver.class) -public class HealthCheckIT { - - private static final System.Logger LOGGER = System.getLogger(HealthCheckIT.class.getName()); - - private final DbClient dbClient; - private final Config config; - private final boolean pingDml; - - HealthCheckIT(DbClient dbClient, Config config) { - this.dbClient = dbClient; - this.config = config; - Config cfgPingDml = config.get("test.ping-dml"); - this.pingDml = cfgPingDml.exists() ? cfgPingDml.asBoolean().get() : true; - } - - /** - * Verify health check implementation with default settings. - */ - @Test - public void testHealthCheck() { - HealthCheck check = DbClientHealthCheck.create(dbClient, config.get("db.health-check")); - HealthCheckResponse response = check.call(); - HealthCheckResponse.Status state = response.status(); - assertThat("Health check failed, response: " + response.details(), state, equalTo(HealthCheckResponse.Status.UP)); - } - - /** - * Verify health check implementation with builder and custom name. - */ - @Test - public void testHealthCheckWithName() { - String hcName = "TestHC"; - HealthCheck check = DbClientHealthCheck.builder(dbClient).config(config.get("db.health-check")).name(hcName).build(); - HealthCheckResponse response = check.call(); - String name = check.name(); - HealthCheckResponse.Status state = response.status(); - assertThat(name, equalTo(hcName)); - assertThat(state, equalTo(HealthCheckResponse.Status.UP)); - } - - /** - * Verify health check implementation using custom DML named statement. - */ - @Test - public void testHealthCheckWithCustomNamedDML() { - if (!pingDml) { - LOGGER.log(Level.DEBUG, () -> String.format("Database %s does not support DML ping, skipping this test", dbClient.dbType())); - return; - } - HealthCheck check = DbClientHealthCheck.builder(dbClient).dml().statementName("ping-dml").build(); - HealthCheckResponse response = check.call(); - HealthCheckResponse.Status state = response.status(); - assertThat("Health check failed, response: " + response.details(), state, equalTo(HealthCheckResponse.Status.UP)); - } - - /** - * Verify health check implementation using custom DML statement. - */ - @Test - public void testHealthCheckWithCustomDML() { - if (!pingDml) { - LOGGER.log(Level.DEBUG, () -> String.format("Database %s does not support DML ping, skipping this test", dbClient.dbType())); - return; - } - Config cfgStatement = config.get("db.statements.ping-dml"); - assertThat("Missing ping-dml statement in database configuration!", cfgStatement.exists(), equalTo(true)); - String statement = cfgStatement.asString().get(); - assertThat("Missing ping-dml statement String in database configuration!", statement, is(notNullValue())); - LOGGER.log(Level.DEBUG, () -> String.format("Using db.statements.ping-dml value %s", statement)); - HealthCheck check = DbClientHealthCheck.builder(dbClient).dml().statement(statement).build(); - HealthCheckResponse response = check.call(); - HealthCheckResponse.Status state = response.status(); - assertThat("Health check failed, response: " + response.details(), state, equalTo(HealthCheckResponse.Status.UP)); - } - - /** - * Verify health check implementation using custom query named statement. - */ - @Test - public void testHealthCheckWithCustomNamedQuery() { - HealthCheck check = DbClientHealthCheck.builder(dbClient).query().statementName("ping-query").build(); - HealthCheckResponse response = check.call(); - HealthCheckResponse.Status state = response.status(); - assertThat("Health check failed, response: " + response.details(), state, equalTo(HealthCheckResponse.Status.UP)); - } - - /** - * Verify health check implementation using custom query statement. - */ - @Test - public void testHealthCheckWithCustomQuery() { - Config cfgStatement = config.get("db.statements.ping-query"); - assertThat("Missing ping-query statement in database configuration!", cfgStatement.exists(), equalTo(true)); - String statement = cfgStatement.asString().get(); - assertThat("Missing ping-query statement String in database configuration!", statement, is(notNullValue())); - LOGGER.log(Level.DEBUG, () -> String.format("Using db.statements.ping-query value %s", statement)); - HealthCheck check = DbClientHealthCheck.builder(dbClient).query().statement(statement).build(); - HealthCheckResponse response = check.call(); - HealthCheckResponse.Status state = response.status(); - assertThat("Health check failed, response: " + response.details(), state, equalTo(HealthCheckResponse.Status.UP)); - } - -} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/InterceptorIT.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/InterceptorIT.java deleted file mode 100644 index 00fa855a673..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/InterceptorIT.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.tests.integration.dbclient.common.tests; - -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbClientService; -import io.helidon.dbclient.DbClientServiceContext; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import static io.helidon.tests.integration.dbclient.common.model.Pokemon.POKEMONS; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - -/** - * Verify services handling. - */ -@ExtendWith(DbClientParameterResolver.class) -public class InterceptorIT { - - private final Config config; - - public InterceptorIT(Config config) { - this.config = config; - } - - private static final class TestClientService implements DbClientService { - - private boolean called; - - private TestClientService() { - this.called = false; - } - - @Override - public DbClientServiceContext statement(DbClientServiceContext context) { - this.called = true; - return context; - } - - private boolean called() { - return called; - } - - } - - /** - * Check that statement interceptor was called before statement execution. - */ - @Test - public void testStatementInterceptor() { - TestClientService interceptor = new TestClientService(); - DbClient dbClient = DbClient.builder(config.get("db")).addService(interceptor).build(); - dbClient.execute() - .createNamedQuery("select-pokemon-named-arg") - .addParam("name", POKEMONS.get(6).getName()) - .execute(); - assertThat(interceptor.called(), equalTo(true)); - } - -} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/MapperIT.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/MapperIT.java deleted file mode 100644 index e3c73e6ed39..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/MapperIT.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.tests.integration.dbclient.common.tests; - -import java.lang.System.Logger.Level; -import java.util.Optional; -import java.util.concurrent.ExecutionException; -import java.util.stream.Stream; - -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbExecute; -import io.helidon.dbclient.DbRow; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.common.utils.TestConfig; - -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import static io.helidon.tests.integration.dbclient.common.model.Pokemon.POKEMONS; -import static io.helidon.tests.integration.dbclient.common.model.Type.TYPES; -import static io.helidon.tests.integration.dbclient.common.utils.VerifyData.verifyInsertPokemon; -import static io.helidon.tests.integration.dbclient.common.utils.VerifyData.verifyPokemon; -import static io.helidon.tests.integration.dbclient.common.utils.VerifyData.verifyUpdatePokemon; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - -/** - * Verify mapping interface. - */ -@SuppressWarnings("SpellCheckingInspection") -@ExtendWith(DbClientParameterResolver.class) -public class MapperIT { - - private static final System.Logger LOGGER = System.getLogger(MapperIT.class.getName()); - private static final int BASE_ID = TestConfig.LAST_POKEMON_ID + 400; - - private final DbClient dbClient; - - MapperIT(DbClient dbClient) { - this.dbClient = dbClient; - } - - private static void addPokemon(DbClient dbClient, Pokemon pokemon) { - POKEMONS.put(pokemon.getId(), pokemon); - long result = dbClient.execute() - .namedInsert("insert-pokemon", pokemon.getId(), pokemon.getName()); - verifyInsertPokemon(dbClient, result, pokemon); - } - - @BeforeAll - public static void setup(DbClient dbClient) throws ExecutionException, InterruptedException { - try { - // BASE_ID+1, 2 is used for inserts - int curId = BASE_ID + 2; - addPokemon(dbClient, new Pokemon(++curId, "Moltres", TYPES.get(3), TYPES.get(10))); // BASE_ID+3 - addPokemon(dbClient, new Pokemon(++curId, "Masquerain", TYPES.get(3), TYPES.get(7))); // BASE_ID+4 - addPokemon(dbClient, new Pokemon(++curId, "Makuhita", TYPES.get(2))); // BASE_ID+5 - addPokemon(dbClient, new Pokemon(++curId, "Hariyama", TYPES.get(2))); // BASE_ID+6 - } catch (Exception ex) { - LOGGER.log(Level.WARNING, String.format("Exception in setup: %s", ex.getMessage()), ex); - throw ex; - } - } - - /** - * Verify insertion of using indexed mapping. - */ - @Test - public void testInsertWithOrderMapping() { - Pokemon pokemon = new Pokemon(BASE_ID + 1, "Articuno", TYPES.get(3), TYPES.get(15)); - long result = dbClient.execute() - .createNamedInsert("insert-pokemon-order-arg-rev") - .indexedParam(pokemon) - .execute(); - verifyInsertPokemon(dbClient, result, pokemon); - } - - /** - * Verify insertion of using named mapping. - */ - @Test - public void testInsertWithNamedMapping() { - Pokemon pokemon = new Pokemon(BASE_ID + 2, "Zapdos", TYPES.get(3), TYPES.get(13)); - long result = dbClient.execute() - .createNamedInsert("insert-pokemon-named-arg") - .namedParam(pokemon) - .execute(); - verifyInsertPokemon(dbClient, result, pokemon); - } - - /** - * Verify update of using indexed mapping. - */ - @Test - public void testUpdateWithOrderMapping() { - Pokemon pokemon = new Pokemon(BASE_ID + 3, "Masquerain", TYPES.get(3), TYPES.get(15)); - long result = dbClient.execute() - .createNamedUpdate("update-pokemon-order-arg") - .indexedParam(pokemon) - .execute(); - verifyUpdatePokemon(dbClient, result, pokemon); - } - - /** - * Verify update of using named mapping. - */ - @Test - public void testUpdateWithNamedMapping() { - Pokemon pokemon = new Pokemon(BASE_ID + 4, "Moltres", TYPES.get(3), TYPES.get(13)); - long result = dbClient.execute() - .createNamedUpdate("update-pokemon-named-arg") - .namedParam(pokemon) - .execute(); - verifyUpdatePokemon(dbClient, result, pokemon); - } - - /** - * Verify delete of using indexed mapping. - */ - @Test - public void testDeleteWithOrderMapping() { - DbExecute exec = dbClient.execute(); - Pokemon pokemon = POKEMONS.get(BASE_ID + 5); - - long result = exec.createNamedDelete("delete-pokemon-full-order-arg") - .indexedParam(pokemon) - .execute(); - - assertThat(result, equalTo(1L)); - Optional maybeRow = exec - .namedGet("select-pokemon-by-id", pokemon.getId()); - assertThat(maybeRow.isPresent(), equalTo(false)); - } - - /** - * Verify delete of using named mapping. - */ - @Test - public void testDeleteWithNamedMapping() { - DbExecute exec = dbClient.execute(); - Pokemon pokemon = POKEMONS.get(BASE_ID + 6); - - long result = exec.createNamedDelete("delete-pokemon-full-named-arg") - .namedParam(pokemon) - .execute(); - - assertThat(result, equalTo(1L)); - Optional maybeRow = exec - .namedGet("select-pokemon-by-id", pokemon.getId()); - assertThat(maybeRow.isPresent(), equalTo(false)); - } - - /** - * Verify query of as a result using mapping. - */ - @Test - public void testQueryWithMapping() { - Stream rows = dbClient.execute() - .createNamedQuery("select-pokemon-named-arg") - .addParam("name", POKEMONS.get(2).getName()) - .execute(); - - Pokemon pokemon = rows.map(it -> it.as(Pokemon.class)).toList().get(0); - verifyPokemon(pokemon, POKEMONS.get(2)); - } - - /** - * Verify get of as a result using mapping. - */ - @Test - public void testGetWithMapping() { - Optional maybeRow = dbClient.execute() - .createNamedGet("select-pokemon-named-arg") - .addParam("name", POKEMONS.get(3).getName()) - .execute(); - - assertThat(maybeRow.isPresent(), equalTo(true)); - Pokemon pokemon = maybeRow.get().as(Pokemon.class); - verifyPokemon(pokemon, POKEMONS.get(3)); - } -} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/QueryStatementIT.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/QueryStatementIT.java deleted file mode 100644 index b23948b881e..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/QueryStatementIT.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (c) 2019, 2024 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.tests.integration.dbclient.common.tests; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; - -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbRow; -import io.helidon.tests.integration.dbclient.common.utils.RangePoJo; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import static io.helidon.tests.integration.dbclient.common.utils.VerifyData.verifyPokemonsIdRange; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.notNullValue; - -/** - * Test DbStatementQuery methods. - */ -@ExtendWith(DbClientParameterResolver.class) -public class QueryStatementIT { - - private final DbClient dbClient; - - QueryStatementIT(DbClient dbClient) { - this.dbClient = dbClient; - } - - /** - * Verify {@code params(Object... parameters)} parameters setting method. - */ - @Test - public void testQueryArrayParams() { - Stream rows = dbClient.execute() - .createNamedQuery("select-pokemons-idrng-order-arg") - .params(1, 7) - .execute(); - - verifyPokemonsIdRange(rows, 1, 7); - } - - /** - * Verify {@code params(List)} parameters setting method. - */ - @Test - public void testQueryListParams() { - List params = new ArrayList<>(2); - params.add(1); - params.add(7); - Stream rows = dbClient.execute() - .createNamedQuery("select-pokemons-idrng-order-arg") - .params(params) - .execute(); - - verifyPokemonsIdRange(rows, 1, 7); - } - - /** - * Verify {@code params(Map)} parameters setting method. - */ - @Test - public void testQueryMapParams() { - Map params = new HashMap<>(2); - params.put("idmin", 1); - params.put("idmax", 7); - Stream rows = dbClient.execute() - .createNamedQuery("select-pokemons-idrng-named-arg") - .params(params) - .execute(); - - verifyPokemonsIdRange(rows, 1, 7); - } - - @Test - public void testQueryMapMissingParams() { - Map params = new HashMap<>(2); - params.put("id", 1); - Stream rows = dbClient.execute() - .createNamedQuery("select-pokemons-idname-named-arg") - .params(params) - .execute(); - assertThat(rows, notNullValue()); - List rowsList = rows.toList(); - assertThat(rowsList, hasSize(0)); - } - - /** - * Verify {@code addParam(Object parameter)} parameters setting method. - */ - @Test - public void testQueryOrderParam() { - Stream rows = dbClient.execute() - .createNamedQuery("select-pokemons-idrng-order-arg") - .addParam(1) - .addParam(7) - .execute(); - - verifyPokemonsIdRange(rows, 1, 7); - } - - /** - * Verify {@code addParam(String name, Object parameter)} parameters setting method. - */ - @Test - public void testQueryNamedParam() { - Stream rows = dbClient.execute() - .createNamedQuery("select-pokemons-idrng-named-arg") - .addParam("idmin", 1) - .addParam("idmax", 7) - .execute(); - - verifyPokemonsIdRange(rows, 1, 7); - } - - /** - * Verify {@code namedParam(Object parameters)} mapped parameters setting method. - */ - @Test - public void testQueryMappedNamedParam() { - RangePoJo range = new RangePoJo(1, 7); - Stream rows = dbClient.execute() - .createNamedQuery("select-pokemons-idrng-named-arg") - .namedParam(range) - .execute(); - - verifyPokemonsIdRange(rows, 1, 7); - } - - /** - * Verify {@code indexedParam(Object parameters)} mapped parameters setting method. - */ - @Test - public void testQueryMappedOrderParam() { - RangePoJo range = new RangePoJo(1, 7); - Stream rows = dbClient.execute() - .createNamedQuery("select-pokemons-idrng-order-arg") - .indexedParam(range) - .execute(); - - verifyPokemonsIdRange(rows, 1, 7); - } - -} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/ServerHealthCheckIT.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/ServerHealthCheckIT.java deleted file mode 100644 index 5a4d10cd63e..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/ServerHealthCheckIT.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.tests.integration.dbclient.common.tests; - -import java.io.IOException; -import java.io.StringReader; -import java.lang.System.Logger.Level; -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; - -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.health.DbClientHealthCheck; -import io.helidon.http.Status; -import io.helidon.webserver.WebServer; -import io.helidon.webserver.WebServerConfig; -import io.helidon.webserver.observe.ObserveFeature; -import io.helidon.webserver.observe.health.HealthObserver; - -import jakarta.json.Json; -import jakarta.json.JsonArray; -import jakarta.json.JsonReader; -import jakarta.json.JsonStructure; -import jakarta.json.stream.JsonParsingException; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.greaterThan; -import static org.junit.jupiter.api.Assertions.fail; - -/** - * Verify health check in web server environment. - */ -@ExtendWith(DbClientParameterResolver.class) -public class ServerHealthCheckIT { - - private static final System.Logger LOGGER = System.getLogger(ServerHealthCheckIT.class.getName()); - - private static WebServer SERVER; - private static String URL; - private final DbClient dbClient; - - public ServerHealthCheckIT(DbClient dbClient) { - this.dbClient = dbClient; - } - - @BeforeAll - public static void setup(DbClient dbClient, Config config) { - SERVER = WebServer.builder() - .update(builder -> routing(dbClient, config, builder)) - .config(config.get("server")) - .build() - .start(); - URL = "http://localhost:" + SERVER.port(); - LOGGER.log(Level.TRACE, () -> "WEB server is running at " + URL); - } - - // Add 2 endpoints: - // - HealthCheck /noDetails/health with details turned off - // - HealthCheck /details/health with details turned on - private static void routing(DbClient dbClient, Config config, WebServerConfig.Builder router) { - router.addFeature( - createObserveFeature(dbClient, config, "healthNoDetails", "noDetails", false)); - router.addFeature( - createObserveFeature(dbClient, config, "healthDetails", "details", true)); - } - - private static ObserveFeature createObserveFeature(DbClient dbClient, Config config, String name, String endpoint, boolean details) { - return ObserveFeature.builder() - .observersDiscoverServices(false) - .endpoint(endpoint) - .name(name) - .addObserver(HealthObserver.builder() - .addCheck(DbClientHealthCheck.builder(dbClient) - .config(config.get("db.health-check")) - .name(name) - .build()) - .details(details) - .build()) - .build(); - } - - @AfterAll - public static void shutdown() { - SERVER.stop(); - LOGGER.log(Level.TRACE, () -> "WEB server stopped"); - } - - /** - * Retrieve server health status from Helidon Web Server. - * - * @param url server health status URL - * @return server health status response (JSON) - * @throws IOException if an I/O error occurs when sending or receiving HTTP request - * @throws InterruptedException if the current thread was interrupted - */ - private static HttpResponse get(String url) throws IOException, InterruptedException { - HttpResponse response; - try (HttpClient client = HttpClient.newHttpClient()) { - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(url)) - .header("Accept", "application/json") - .build(); - response = client.send(request, HttpResponse.BodyHandlers.ofString()); - } - return response; - } - - /** - * Read and check Database Client health status from Helidon Web Server. - * - * @throws InterruptedException if the current thread was interrupted - * @throws IOException if an I/O error occurs when sending or receiving HTTP request - */ - @Test - void testHttpHealthNoDetails() throws IOException, InterruptedException { - // Call select-pokemons to warm up server - dbClient.execute().namedQuery("select-pokemons").forEach(it -> {}); - String url = URL + "/noDetails/health"; - // Read and process health check response - HttpResponse response = get(url); - LOGGER.log(Level.TRACE, () -> String.format("%s RESPONSE: %d", response.statusCode())); - assertThat(response.statusCode(), equalTo(Status.NO_CONTENT_204.code())); - } - - /** - * Read and check Database Client health status from Helidon Web Server. - * - * @throws InterruptedException if the current thread was interrupted - * @throws IOException if an I/O error occurs when sending or receiving HTTP request - */ - @Test - void testHttpHealthDetails() throws IOException, InterruptedException { - // Call select-pokemons to warm up server - dbClient.execute().namedQuery("select-pokemons").forEach(it -> {}); - String url = URL + "/details/health"; - // Read and process health check response - HttpResponse response = get(url); - assertThat(response.statusCode(), equalTo(Status.OK_200.code())); - String jsonSrc = response.body(); - LOGGER.log(Level.TRACE, () -> String.format("%s RESPONSE: %s", url, jsonSrc)); - JsonStructure jsonResponse = null; - try (JsonReader jr = Json.createReader(new StringReader(jsonSrc))) { - jsonResponse = jr.read(); - } catch (JsonParsingException | IllegalStateException ex) { - fail(String.format("Error parsing response: %s", ex.getMessage())); - } - JsonArray checks = jsonResponse.asJsonObject().getJsonArray("checks"); - assertThat(checks.size(), greaterThan(0)); - checks.forEach((check) -> { - String status = check.asJsonObject().getString("status"); - assertThat(status, equalTo("UP")); - }); - } - -} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/ServerMetricsCheckIT.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/ServerMetricsCheckIT.java deleted file mode 100644 index ea0bc2a2e62..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/ServerMetricsCheckIT.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.tests.integration.dbclient.common.tests; - -import java.io.IOException; -import java.io.StringReader; -import java.lang.System.Logger.Level; -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; - -import io.helidon.common.config.GlobalConfig; -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbStatementType; -import io.helidon.dbclient.metrics.DbClientMetrics; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.common.utils.TestConfig; -import io.helidon.webserver.WebServer; - -import jakarta.json.Json; -import jakarta.json.JsonObject; -import jakarta.json.JsonReader; -import jakarta.json.JsonValue; -import jakarta.json.stream.JsonParsingException; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import static io.helidon.tests.integration.dbclient.common.model.Type.TYPES; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.jupiter.api.Assertions.fail; - -/** - * Verify metrics check in web server environment. - */ -@SuppressWarnings("SpellCheckingInspection") -@ExtendWith(DbClientParameterResolver.class) -public class ServerMetricsCheckIT { - - private static final System.Logger LOGGER = System.getLogger(ServerMetricsCheckIT.class.getName()); - private static final int BASE_ID = TestConfig.LAST_POKEMON_ID + 300; - - private static DbClient DB_CLIENT; - private static WebServer SERVER; - private static String URL; - - private static DbClient initDbClient(Config config) { - Config dbConfig = config.get("db"); - return DbClient.builder(dbConfig) - // add an interceptor to named statement(s) - .addService(DbClientMetrics.counter() - .statementNames("select-pokemons", "insert-pokemon")) - // add an interceptor to statement type(s) - .addService(DbClientMetrics.timer() - .statementTypes(DbStatementType.INSERT)) - .build(); - } - - @BeforeAll - public static void startup(Config config) { - GlobalConfig.config(() -> config); - DB_CLIENT = initDbClient(config); - SERVER = WebServer.builder() - .config(config.get("server")) - .build() - .start(); - URL = "http://localhost:" + SERVER.port(); - LOGGER.log(Level.TRACE, () -> "WEB server is running at " + URL); - } - - @AfterAll - public static void shutdown() { - if (null != SERVER) { - SERVER.stop(); - LOGGER.log(Level.TRACE, () -> "WEB server stopped"); - } - } - - /** - * Retrieve server metrics status from Helidon Web Server. - * - * @param url server health status URL - * @return server health status response (JSON) - * @throws IOException if an I/O error occurs when sending or receiving HTTP request - * @throws InterruptedException if the current thread was interrupted - */ - private static String get(String url) throws IOException, InterruptedException { - HttpClient client = HttpClient.newHttpClient(); - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(url)) - .header("Accept", "application/json") - .build(); - HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); - return response.body(); - } - - /** - * Read and check Database Client metrics from Helidon Web Server. - * - * @throws InterruptedException if the current thread was interrupted - * @throws IOException if an I/O error occurs when sending or receiving HTTP request - */ - @Test - public void testHttpMetrics() throws IOException, InterruptedException { - // Call select-pokemons to trigger it - - DB_CLIENT.execute() - .namedQuery("select-pokemons") - .forEach(p -> { - }); - - // Call insert-pokemon to trigger it - Pokemon pokemon = new Pokemon(BASE_ID + 1, "Lickitung", TYPES.get(1)); - DB_CLIENT.execute() - .namedInsert("insert-pokemon", pokemon.getId(), pokemon.getName()); - // Read and process metrics response - String response = get(URL + "/observe/metrics/application"); - LOGGER.log(Level.TRACE, () -> String.format("RESPONSE: %s", response)); - JsonObject application = null; - try (JsonReader jr = Json.createReader(new StringReader(response))) { - application = jr.readObject(); - } catch (JsonParsingException | IllegalStateException ex) { - fail(String.format("Error parsing response: %s", ex.getMessage())); - } - assertThat(application, notNullValue()); - assertThat(application.getValueType(), equalTo(JsonValue.ValueType.OBJECT)); - - assertThat(application.size(), greaterThan(0)); - assertThat(application.containsKey("db.counter.select-pokemons"), equalTo(true)); - assertThat(application.containsKey("db.counter.insert-pokemon"), equalTo(true)); - int selectPokemons = application.getInt("db.counter.select-pokemons"); - int insertPokemons = application.getInt("db.counter.insert-pokemon"); - assertThat(selectPokemons, equalTo(1)); - assertThat(insertPokemons, equalTo(1)); - assertThat(application.containsKey("db.timer.insert-pokemon"), equalTo(true)); - JsonObject insertTimer = application.getJsonObject("db.timer.insert-pokemon"); - assertThat(insertTimer.containsKey("count"), equalTo(true)); - assertThat(insertTimer.containsKey("mean"), equalTo(true)); - assertThat(insertTimer.containsKey("max"), equalTo(true)); - int timerCount = insertTimer.getInt("count"); - assertThat(timerCount, equalTo(1)); - } - -} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/SimpleDeleteIT.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/SimpleDeleteIT.java deleted file mode 100644 index f2b657c0ce5..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/SimpleDeleteIT.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.tests.integration.dbclient.common.tests; - -import java.lang.System.Logger.Level; -import java.util.HashMap; -import java.util.Map; - -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.common.utils.TestConfig; - -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import static io.helidon.tests.integration.dbclient.common.model.Type.TYPES; -import static io.helidon.tests.integration.dbclient.common.utils.VerifyData.verifyDeletePokemon; -import static io.helidon.tests.integration.dbclient.common.utils.VerifyData.verifyInsertPokemon; - -/** - * Test set of basic JDBC delete calls. - */ -@SuppressWarnings("SpellCheckingInspection") -@ExtendWith(DbClientParameterResolver.class) -public class SimpleDeleteIT { - - private static final System.Logger LOGGER = System.getLogger(SimpleDeleteIT.class.getName()); - private static final int BASE_ID = TestConfig.LAST_POKEMON_ID + 30; - private static final Map POKEMONS = new HashMap<>(); - - private final DbClient dbClient; - private final Config config; - - public SimpleDeleteIT(DbClient dbClient, Config config) { - this.dbClient = dbClient; - this.config = config; - } - - private static void addPokemon(DbClient dbClient, Pokemon pokemon) { - POKEMONS.put(pokemon.getId(), pokemon); - long result = dbClient.execute() - .namedInsert("insert-pokemon", pokemon.getId(), pokemon.getName()); - verifyInsertPokemon(dbClient, result, pokemon); - } - - @BeforeAll - public static void setup(DbClient dbClient) { - try { - int curId = BASE_ID; - addPokemon(dbClient, new Pokemon(++curId, "Rayquaza", TYPES.get(3), TYPES.get(16))); // BASE_ID+1 - addPokemon(dbClient, new Pokemon(++curId, "Lugia", TYPES.get(3), TYPES.get(14))); // BASE_ID+2 - addPokemon(dbClient, new Pokemon(++curId, "Ho-Oh", TYPES.get(3), TYPES.get(10))); // BASE_ID+3 - addPokemon(dbClient, new Pokemon(++curId, "Raikou", TYPES.get(13))); // BASE_ID+4 - addPokemon(dbClient, new Pokemon(++curId, "Giratina", TYPES.get(8), TYPES.get(16))); // BASE_ID+5 - addPokemon(dbClient, new Pokemon(++curId, "Regirock", TYPES.get(6))); // BASE_ID+6 - addPokemon(dbClient, new Pokemon(++curId, "Kyogre", TYPES.get(11))); // BASE_ID+7 - } catch (Exception ex) { - LOGGER.log(Level.WARNING, String.format("Exception in setup: %s", ex)); - throw ex; - } - } - - - /** - * Verify {@code createNamedDelete(String, String)} API method with ordered parameters. - */ - @Test - public void testCreateNamedDeleteStrStrOrderArgs() { - String stmt = config.get("db.statements.delete-pokemon-order-arg").asString().get(); - long result = dbClient.execute() - .createNamedDelete("delete-rayquaza", stmt) - .addParam(POKEMONS.get(BASE_ID + 1).getId()).execute(); - verifyDeletePokemon(dbClient, result, POKEMONS.get(BASE_ID + 1)); - } - - /** - * Verify {@code createNamedDelete(String)} API method with named parameters. - */ - @Test - public void testCreateNamedDeleteStrNamedArgs() { - long result = dbClient.execute() - .createNamedDelete("delete-pokemon-named-arg") - .addParam("id", POKEMONS.get(BASE_ID + 2).getId()).execute(); - verifyDeletePokemon(dbClient, result, POKEMONS.get(BASE_ID + 2)); - } - - /** - * Verify {@code createNamedDelete(String)} API method with ordered parameters. - */ - @Test - public void testCreateNamedDeleteStrOrderArgs() { - long result = dbClient.execute() - .createNamedDelete("delete-pokemon-order-arg") - .addParam(POKEMONS.get(BASE_ID + 3).getId()).execute(); - verifyDeletePokemon(dbClient, result, POKEMONS.get(BASE_ID + 3)); - } - - /** - * Verify {@code createDelete(String)} API method with named parameters. - */ - @Test - public void testCreateDeleteNamedArgs() { - String stmt = config.get("db.statements.delete-pokemon-named-arg").asString().get(); - long result = dbClient.execute() - .createDelete(stmt) - .addParam("id", POKEMONS.get(BASE_ID + 4).getId()).execute(); - verifyDeletePokemon(dbClient, result, POKEMONS.get(BASE_ID + 4)); - } - - /** - * Verify {@code createDelete(String)} API method with ordered parameters. - */ - @Test - public void testCreateDeleteOrderArgs() { - String stmt = config.get("db.statements.delete-pokemon-order-arg").asString().get(); - long result = dbClient.execute() - .createDelete(stmt) - .addParam(POKEMONS.get(BASE_ID + 5).getId()).execute(); - verifyDeletePokemon(dbClient, result, POKEMONS.get(BASE_ID + 5)); - } - - /** - * Verify {@code namedDelete(String)} API method with ordered parameters. - */ - @Test - public void testNamedDeleteOrderArgs() { - long result = dbClient.execute() - .namedDelete("delete-pokemon-order-arg", POKEMONS.get(BASE_ID + 6).getId()); - verifyDeletePokemon(dbClient, result, POKEMONS.get(BASE_ID + 6)); - } - - /** - * Verify {@code delete(String)} API method with ordered parameters. - */ - @Test - public void testDeleteOrderArgs() { - String stmt = config.get("db.statements.delete-pokemon-order-arg").asString().get(); - long result = dbClient.execute() - .delete(stmt, POKEMONS.get(BASE_ID + 7).getId()); - verifyDeletePokemon(dbClient, result, POKEMONS.get(BASE_ID + 7)); - } - -} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/SimpleDmlIT.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/SimpleDmlIT.java deleted file mode 100644 index 95b7fb1d505..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/SimpleDmlIT.java +++ /dev/null @@ -1,368 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.tests.integration.dbclient.common.tests; - -import java.lang.System.Logger.Level; -import java.util.HashMap; -import java.util.Map; - -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.common.utils.TestConfig; - -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import static io.helidon.tests.integration.dbclient.common.model.Type.TYPES; -import static io.helidon.tests.integration.dbclient.common.utils.VerifyData.verifyDeletePokemon; -import static io.helidon.tests.integration.dbclient.common.utils.VerifyData.verifyInsertPokemon; -import static io.helidon.tests.integration.dbclient.common.utils.VerifyData.verifyUpdatePokemon; - -/** - * Test set of basic JDBC DML statement calls. - */ -@SuppressWarnings("SpellCheckingInspection") -@ExtendWith(DbClientParameterResolver.class) -public class SimpleDmlIT { - - private static final System.Logger LOGGER = System.getLogger(SimpleDmlIT.class.getName()); - private static final int BASE_ID = TestConfig.LAST_POKEMON_ID + 40; - private static final Map POKEMONS = new HashMap<>(); - private final DbClient dbClient; - private final Config config; - - public SimpleDmlIT(DbClient dbClient, Config config) { - this.dbClient = dbClient; - this.config = config; - } - - private static void addPokemon(DbClient dbClient, Pokemon pokemon) { - POKEMONS.put(pokemon.getId(), pokemon); - long result = dbClient.execute() - .namedInsert("insert-pokemon", pokemon.getId(), pokemon.getName()); - verifyInsertPokemon(dbClient, result, pokemon); - } - - @BeforeAll - public static void setup(DbClient dbClient) { - try { - // [BASE_ID + 1 .. BASE_ID + 9] is reserved for inserts - // [BASE_ID + 10 .. BASE_ID + 19] are reserved for updates - addPokemon(dbClient, new Pokemon(BASE_ID + 10, "Piplup", TYPES.get(11))); // BASE_ID+10 - addPokemon(dbClient, new Pokemon(BASE_ID + 11, "Prinplup", TYPES.get(11))); // BASE_ID+11 - addPokemon(dbClient, new Pokemon(BASE_ID + 12, "Empoleon", TYPES.get(9), TYPES.get(11))); // BASE_ID+12 - addPokemon(dbClient, new Pokemon(BASE_ID + 13, "Staryu", TYPES.get(11))); // BASE_ID+13 - addPokemon(dbClient,new Pokemon(BASE_ID + 14, "Starmie", TYPES.get(11), TYPES.get(14))); // BASE_ID+14 - addPokemon(dbClient,new Pokemon(BASE_ID + 15, "Horsea", TYPES.get(11))); // BASE_ID+15 - addPokemon(dbClient,new Pokemon(BASE_ID + 16, "Seadra", TYPES.get(11))); // BASE_ID+16 - // BASE_ID + 20 .. BASE_ID + 29 are reserved for deletes - addPokemon(dbClient,new Pokemon(BASE_ID + 20, "Mudkip", TYPES.get(11))); // BASE_ID+20 - addPokemon(dbClient,new Pokemon(BASE_ID + 21, "Marshtomp", TYPES.get(5), TYPES.get(11))); // BASE_ID+21 - addPokemon(dbClient,new Pokemon(BASE_ID + 22, "Swampert", TYPES.get(5), TYPES.get(11))); // BASE_ID+22 - addPokemon(dbClient,new Pokemon(BASE_ID + 23, "Muk", TYPES.get(4))); // BASE_ID+23 - addPokemon(dbClient,new Pokemon(BASE_ID + 24, "Grimer", TYPES.get(4))); // BASE_ID+24 - addPokemon(dbClient,new Pokemon(BASE_ID + 25, "Cubchoo", TYPES.get(15))); // BASE_ID+25 - addPokemon(dbClient,new Pokemon(BASE_ID + 26, "Beartic", TYPES.get(15))); // BASE_ID+26 - } catch (Exception ex) { - LOGGER.log(Level.WARNING, String.format("Exception in setup: %s", ex)); - throw ex; - } - } - - /** - * Verify {@code createNamedDmlStatement(String, String)} API method with insert with named parameters. - */ - @Test - public void testCreateNamedDmlWithInsertStrStrNamedArgs() { - Pokemon pokemon = new Pokemon(BASE_ID + 1, "Torchic", TYPES.get(10)); - String stmt = config.get("db.statements.insert-pokemon-named-arg").asString().get(); - long result = dbClient.execute() - .createNamedDmlStatement("insert-torchic", stmt) - .addParam("id", pokemon.getId()).addParam("name", pokemon.getName()) - .execute(); - verifyInsertPokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code createNamedDmlStatement(String)} API method with insert with named parameters. - */ - @Test - public void testCreateNamedDmlWithInsertStrNamedArgs() { - Pokemon pokemon = new Pokemon(BASE_ID + 2, "Combusken", TYPES.get(2), TYPES.get(10)); - long result = dbClient.execute() - .createNamedDmlStatement("insert-pokemon-named-arg") - .addParam("id", pokemon.getId()).addParam("name", pokemon.getName()) - .execute(); - verifyInsertPokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code createNamedDmlStatement(String)} API method with insert with ordered parameters. - */ - @Test - public void testCreateNamedDmlWithInsertStrOrderArgs() { - Pokemon pokemon = new Pokemon(BASE_ID + 3, "Treecko", TYPES.get(12)); - long result = dbClient.execute() - .createNamedDmlStatement("insert-pokemon-order-arg") - .addParam(pokemon.getId()).addParam(pokemon.getName()) - .execute(); - verifyInsertPokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code createDmlStatement(String)} API method with insert with named parameters. - */ - @Test - public void testCreateDmlWithInsertNamedArgs() { - Pokemon pokemon = new Pokemon(BASE_ID + 4, "Grovyle", TYPES.get(12)); - String stmt = config.get("db.statements.insert-pokemon-named-arg").asString().get(); - long result = dbClient.execute() - .createDmlStatement(stmt) - .addParam("id", pokemon.getId()).addParam("name", pokemon.getName()) - .execute(); - verifyInsertPokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code createDmlStatement(String)} API method with insert with ordered parameters. - */ - @Test - public void testCreateDmlWithInsertOrderArgs() { - Pokemon pokemon = new Pokemon(BASE_ID + 5, "Sceptile", TYPES.get(12)); - String stmt = config.get("db.statements.insert-pokemon-order-arg").asString().get(); - long result = dbClient.execute() - .createDmlStatement(stmt) - .addParam(pokemon.getId()).addParam(pokemon.getName()) - .execute(); - verifyInsertPokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code namedDml(String)} API method with insert with ordered parameters passed directly - * to the {@code insert} method. - */ - @Test - public void testNamedDmlWithInsertOrderArgs() { - Pokemon pokemon = new Pokemon(BASE_ID + 6, "Snover", TYPES.get(12), TYPES.get(15)); - long result = dbClient.execute() - .namedDml("insert-pokemon-order-arg", pokemon.getId(), pokemon.getName()); - verifyInsertPokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code dml(String)} API method with insert with ordered parameters passed directly - * to the {@code insert} method. - */ - @Test - public void testDmlWithInsertOrderArgs() { - Pokemon pokemon = new Pokemon(BASE_ID + 7, "Abomasnow", TYPES.get(12), TYPES.get(15)); - String stmt = config.get("db.statements.insert-pokemon-order-arg").asString().get(); - long result = dbClient.execute() - .dml(stmt, pokemon.getId(), pokemon.getName()); - verifyInsertPokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code createNamedDmlStatement(String, String)} API method with update with named parameters. - */ - @Test - public void testCreateNamedDmlWithUpdateStrStrNamedArgs() { - Pokemon srcPokemon = POKEMONS.get(BASE_ID + 10); - Pokemon updatedPokemon = new Pokemon(BASE_ID + 10, "Prinplup", srcPokemon.getTypesArray()); - String stmt = config.get("db.statements.update-pokemon-named-arg").asString().get(); - long result = dbClient.execute() - .createNamedDmlStatement("update-piplup", stmt) - .addParam("name", updatedPokemon.getName()).addParam("id", updatedPokemon.getId()) - .execute(); - verifyUpdatePokemon(dbClient, result, updatedPokemon); - } - - /** - * Verify {@code createNamedDmlStatement(String)} API method with update with named parameters. - */ - @Test - public void testCreateNamedDmlWithUpdateStrNamedArgs() { - Pokemon srcPokemon = POKEMONS.get(BASE_ID + 11); - Pokemon updatedPokemon = new Pokemon(BASE_ID + 11, "Empoleon", srcPokemon.getTypesArray()); - long result = dbClient.execute() - .createNamedDmlStatement("update-pokemon-named-arg") - .addParam("name", updatedPokemon.getName()).addParam("id", updatedPokemon.getId()) - .execute(); - verifyUpdatePokemon(dbClient, result, updatedPokemon); - } - - /** - * Verify {@code createNamedDmlStatement(String)} API method with update with ordered parameters. - */ - @Test - public void testCreateNamedDmlWithUpdateStrOrderArgs() { - Pokemon srcPokemon = POKEMONS.get(BASE_ID + 12); - Pokemon updatedPokemon = new Pokemon(BASE_ID + 12, "Piplup", srcPokemon.getTypesArray()); - long result = dbClient.execute() - .createNamedDmlStatement("update-pokemon-order-arg") - .addParam(updatedPokemon.getName()).addParam(updatedPokemon.getId()) - .execute(); - verifyUpdatePokemon(dbClient, result, updatedPokemon); - } - - /** - * Verify {@code createDmlStatement(String)} API method with update with named parameters. - */ - @Test - public void testCreateDmlWithUpdateNamedArgs() { - Pokemon srcPokemon = POKEMONS.get(BASE_ID + 13); - Pokemon updatedPokemon = new Pokemon(BASE_ID + 13, "Starmie", srcPokemon.getTypesArray()); - String stmt = config.get("db.statements.update-pokemon-named-arg").asString().get(); - long result = dbClient.execute() - .createDmlStatement(stmt) - .addParam("name", updatedPokemon.getName()).addParam("id", updatedPokemon.getId()) - .execute(); - verifyUpdatePokemon(dbClient, result, updatedPokemon); - } - - /** - * Verify {@code createDmlStatement(String)} API method with update with ordered parameters. - */ - @Test - public void testCreateDmlWithUpdateOrderArgs() { - Pokemon srcPokemon = POKEMONS.get(BASE_ID + 14); - Pokemon updatedPokemon = new Pokemon(BASE_ID + 14, "Staryu", srcPokemon.getTypesArray()); - String stmt = config.get("db.statements.update-pokemon-order-arg").asString().get(); - long result = dbClient.execute() - .createDmlStatement(stmt) - .addParam(updatedPokemon.getName()).addParam(updatedPokemon.getId()) - .execute(); - verifyUpdatePokemon(dbClient, result, updatedPokemon); - } - - /** - * Verify {@code namedDml(String)} API method with update with ordered parameters passed directly - * to the {@code insert} method. - */ - @Test - public void testNamedDmlWithUpdateOrderArgs() { - Pokemon srcPokemon = POKEMONS.get(BASE_ID + 15); - Pokemon updatedPokemon = new Pokemon(BASE_ID + 15, "Seadra", srcPokemon.getTypesArray()); - long result = dbClient.execute() - .namedDml("update-pokemon-order-arg", updatedPokemon.getName(), updatedPokemon.getId()); - verifyUpdatePokemon(dbClient, result, updatedPokemon); - } - - /** - * Verify {@code dml(String)} API method with update with ordered parameters passed directly - * to the {@code insert} method. - */ - @Test - public void testDmlWithUpdateOrderArgs() { - Pokemon srcPokemon = POKEMONS.get(BASE_ID + 16); - Pokemon updatedPokemon = new Pokemon(BASE_ID + 16, "Horsea", srcPokemon.getTypesArray()); - String stmt = config.get("db.statements.update-pokemon-order-arg").asString().get(); - long result = dbClient.execute() - .dml(stmt, updatedPokemon.getName(), updatedPokemon.getId()); - verifyUpdatePokemon(dbClient, result, updatedPokemon); - } - - /** - * Verify {@code createNamedDmlStatement(String, String)} API method with delete with ordered parameters. - */ - @Test - public void testCreateNamedDmlWithDeleteStrStrOrderArgs() { - Pokemon pokemon = POKEMONS.get(BASE_ID + 20); - String stmt = config.get("db.statements.delete-pokemon-order-arg").asString().get(); - long result = dbClient.execute() - .createNamedDmlStatement("delete-mudkip", stmt) - .addParam(pokemon.getId()) - .execute(); - verifyDeletePokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code createNamedDmlStatement(String)} API method with delete with named parameters. - */ - @Test - public void testCreateNamedDmlWithDeleteStrNamedArgs() { - Pokemon pokemon = POKEMONS.get(BASE_ID + 21); - long result = dbClient.execute() - .createNamedDmlStatement("delete-pokemon-named-arg") - .addParam("id", pokemon.getId()) - .execute(); - verifyDeletePokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code createNamedDmlStatement(String)} API method with delete with ordered parameters. - */ - @Test - public void testCreateNamedDmlWithDeleteStrOrderArgs() { - Pokemon pokemon = POKEMONS.get(BASE_ID + 22); - long result = dbClient.execute() - .createNamedDmlStatement("delete-pokemon-order-arg") - .addParam(pokemon.getId()) - .execute(); - verifyDeletePokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code createDmlStatement(String)} API method with delete with named parameters. - */ - @Test - public void testCreateDmlWithDeleteNamedArgs() { - Pokemon pokemon = POKEMONS.get(BASE_ID + 23); - String stmt = config.get("db.statements.delete-pokemon-named-arg").asString().get(); - long result = dbClient.execute() - .createDmlStatement(stmt) - .addParam("id", pokemon.getId()) - .execute(); - verifyDeletePokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code createDmlStatement(String)} API method with delete with ordered parameters. - */ - @Test - public void testCreateDmlWithDeleteOrderArgs() { - Pokemon pokemon = POKEMONS.get(BASE_ID + 24); - String stmt = config.get("db.statements.delete-pokemon-order-arg").asString().get(); - long result = dbClient.execute() - .createDmlStatement(stmt) - .addParam(pokemon.getId()) - .execute(); - verifyDeletePokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code namedDml(String)} API method with delete with ordered parameters. - */ - @Test - public void testNamedDmlWithDeleteOrderArgs() { - Pokemon pokemon = POKEMONS.get(BASE_ID + 25); - long result = dbClient.execute().namedDml("delete-pokemon-order-arg", pokemon.getId()); - verifyDeletePokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code dml(String)} API method with delete with ordered parameters. - */ - @Test - public void testDmlWithDeleteOrderArgs() { - Pokemon pokemon = POKEMONS.get(BASE_ID + 26); - String stmt = config.get("db.statements.delete-pokemon-order-arg").asString().get(); - long result = dbClient.execute().dml(stmt, pokemon.getId()); - verifyDeletePokemon(dbClient, result, pokemon); - } -} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/SimpleGetIT.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/SimpleGetIT.java deleted file mode 100644 index 07ba959e42a..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/SimpleGetIT.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.tests.integration.dbclient.common.tests; - -import java.util.Optional; - -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbRow; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import static io.helidon.tests.integration.dbclient.common.model.Pokemon.POKEMONS; -import static io.helidon.tests.integration.dbclient.common.utils.VerifyData.verifyPokemon; - -/** - * Test set of basic JDBC get calls. - */ -@ExtendWith(DbClientParameterResolver.class) -public class SimpleGetIT { - - private final DbClient dbClient; - private final Config config; - - public SimpleGetIT(DbClient dbClient, Config config) { - this.dbClient = dbClient; - this.config = config; - } - - /** - * Verify {@code createNamedGet(String, String)} API method with named parameters. - */ - @Test - public void testCreateNamedGetStrStrNamedArgs() { - String stmt = config.get("db.statements.select-pokemon-named-arg").asString().get(); - Optional maybeRow = - dbClient.execute().createNamedGet("select-pikachu", stmt) - .addParam("name", POKEMONS.get(1).getName()) - .execute(); - verifyPokemon(maybeRow, POKEMONS.get(1)); - } - - /** - * Verify {@code createNamedGet(String)} API method with named parameters. - */ - @Test - public void testCreateNamedGetStrNamedArgs() { - Optional maybeRow = dbClient.execute() - .createNamedGet("select-pokemon-named-arg") - .addParam("name", POKEMONS.get(2).getName()) - .execute(); - verifyPokemon(maybeRow, POKEMONS.get(2)); - } - - /** - * Verify {@code createNamedGet(String)} API method with ordered parameters. - */ - @Test - public void testCreateNamedGetStrOrderArgs() { - Optional maybeRow = dbClient.execute() - .createNamedGet("select-pokemon-order-arg") - .addParam(POKEMONS.get(3).getName()) - .execute(); - verifyPokemon(maybeRow, POKEMONS.get(3)); - } - - /** - * Verify {@code createGet(String)} API method with named parameters. - */ - @Test - public void testCreateGetNamedArgs() { - String stmt = config.get("db.statements.select-pokemon-named-arg").asString().get(); - Optional maybeRow = dbClient.execute() - .createGet(stmt) - .addParam("name", POKEMONS.get(4).getName()) - .execute(); - verifyPokemon(maybeRow, POKEMONS.get(4)); - } - - /** - * Verify {@code createGet(String)} API method with ordered parameters. - */ - @Test - public void testCreateGetOrderArgs() { - String stmt = config.get("db.statements.select-pokemon-order-arg").asString().get(); - Optional maybeRow = dbClient.execute() - .createGet(stmt) - .addParam(POKEMONS.get(5).getName()) - .execute(); - verifyPokemon(maybeRow, POKEMONS.get(5)); - } - - /** - * Verify {@code namedGet(String)} API method with ordered parameters passed directly to the {@code query} method. - */ - @Test - public void testNamedGetStrOrderArgs() { - Optional maybeRow = dbClient.execute() - .namedGet("select-pokemon-order-arg", POKEMONS.get(6).getName()); - verifyPokemon(maybeRow, POKEMONS.get(6)); - } - - /** - * Verify {@code get(String)} API method with ordered parameters passed directly to the {@code query} method. - */ - @Test - public void testGetStrOrderArgs() { - String stmt = config.get("db.statements.select-pokemon-order-arg").asString().get(); - Optional maybeRow = dbClient.execute() - .get(stmt, POKEMONS.get(7).getName()); - verifyPokemon(maybeRow, POKEMONS.get(7)); - } -} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/SimpleInsertIT.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/SimpleInsertIT.java deleted file mode 100644 index de26e70a6e7..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/SimpleInsertIT.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.tests.integration.dbclient.common.tests; - -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.common.utils.TestConfig; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import static io.helidon.tests.integration.dbclient.common.model.Type.TYPES; -import static io.helidon.tests.integration.dbclient.common.utils.VerifyData.verifyInsertPokemon; - -/** - * Test set of basic JDBC inserts. - */ -@SuppressWarnings("SpellCheckingInspection") -@ExtendWith(DbClientParameterResolver.class) -public class SimpleInsertIT { - - /** - * Maximum Pokemon ID. - */ - private static final int BASE_ID = TestConfig.LAST_POKEMON_ID + 10; - - private final DbClient dbClient; - private final Config config; - - public SimpleInsertIT(DbClient dbClient, Config config) { - this.dbClient = dbClient; - this.config = config; - } - - /** - * Verify {@code createNamedInsert(String, String)} API method with named parameters. - */ - @Test - public void testCreateNamedInsertStrStrNamedArgs() { - Pokemon pokemon = new Pokemon(BASE_ID + 1, "Bulbasaur", TYPES.get(4), TYPES.get(12)); - String stmt = config.get("db.statements.insert-pokemon-named-arg").asString().get(); - long result = dbClient.execute() - .createNamedInsert("insert-bulbasaur", stmt) - .addParam("id", pokemon.getId()).addParam("name", pokemon.getName()) - .execute(); - verifyInsertPokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code createNamedInsert(String)} API method with named parameters. - */ - @Test - public void testCreateNamedInsertStrNamedArgs() { - Pokemon pokemon = new Pokemon(BASE_ID + 2, "Ivysaur", TYPES.get(4), TYPES.get(12)); - long result = dbClient.execute() - .createNamedInsert("insert-pokemon-named-arg") - .addParam("id", pokemon.getId()).addParam("name", pokemon.getName()) - .execute(); - verifyInsertPokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code createNamedInsert(String)} API method with ordered parameters. - */ - @Test - public void testCreateNamedInsertStrOrderArgs() { - Pokemon pokemon = new Pokemon(BASE_ID + 3, "Venusaur", TYPES.get(4), TYPES.get(12)); - long result = dbClient.execute() - .createNamedInsert("insert-pokemon-order-arg") - .addParam(pokemon.getId()).addParam(pokemon.getName()) - .execute(); - verifyInsertPokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code createInsert(String)} API method with named parameters. - */ - @Test - public void testCreateInsertNamedArgs() { - Pokemon pokemon = new Pokemon(BASE_ID + 4, "Magby", TYPES.get(10)); - String stmt = config.get("db.statements.insert-pokemon-named-arg").asString().get(); - long result = dbClient.execute() - .createInsert(stmt) - .addParam("id", pokemon.getId()).addParam("name", pokemon.getName()) - .execute(); - verifyInsertPokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code createInsert(String)} API method with ordered parameters. - */ - @Test - public void testCreateInsertOrderArgs() { - Pokemon pokemon = new Pokemon(BASE_ID + 5, "Magmar", TYPES.get(10)); - String stmt = config.get("db.statements.insert-pokemon-order-arg").asString().get(); - long result = dbClient.execute() - .createInsert(stmt) - .addParam(pokemon.getId()).addParam(pokemon.getName()) - .execute(); - verifyInsertPokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code namedInsert(String)} API method with ordered parameters passed directly to the {@code insert} method. - */ - @Test - public void testNamedInsertOrderArgs() { - Pokemon pokemon = new Pokemon(BASE_ID + 6, "Rattata", TYPES.get(1)); - long result = dbClient.execute().namedInsert("insert-pokemon-order-arg", pokemon.getId(), pokemon.getName()); - verifyInsertPokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code insert(String)} API method with ordered parameters passed directly to the {@code insert} method. - */ - @Test - public void testInsertOrderArgs() { - Pokemon pokemon = new Pokemon(BASE_ID + 7, "Raticate", TYPES.get(1)); - String stmt = config.get("db.statements.insert-pokemon-order-arg").asString().get(); - long result = dbClient.execute().insert(stmt, pokemon.getId(), pokemon.getName()); - verifyInsertPokemon(dbClient, result, pokemon); - } - -} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/SimpleQueriesIT.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/SimpleQueriesIT.java deleted file mode 100644 index 10d355205db..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/SimpleQueriesIT.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.tests.integration.dbclient.common.tests; - -import java.util.stream.Stream; - -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbRow; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import static io.helidon.tests.integration.dbclient.common.model.Pokemon.POKEMONS; -import static io.helidon.tests.integration.dbclient.common.utils.VerifyData.verifyPokemon; - -/** - * Test set of basic JDBC queries. - */ -@ExtendWith(DbClientParameterResolver.class) -public class SimpleQueriesIT { - - private final DbClient dbClient; - private final Config config; - - public SimpleQueriesIT(DbClient dbClient, Config config) { - this.dbClient = dbClient; - this.config = config; - } - - /** - * Verify {@code createNamedQuery(String, String)} API method with ordered parameters. - */ - @Test - public void testCreateNamedQueryStrStrOrderArgs() { - String stmt = config.get("db.statements.select-pokemon-order-arg").asString().get(); - Stream rows = dbClient.execute() - .createNamedQuery("select-pikachu", stmt) - .addParam(POKEMONS.get(1).getName()) - .execute(); - - verifyPokemon(rows, POKEMONS.get(1)); - } - - /** - * Verify {@code createNamedQuery(String)} API method with named parameters. - */ - @Test - public void testCreateNamedQueryStrNamedArgs() { - Stream rows = dbClient.execute() - .createNamedQuery("select-pokemon-named-arg") - .addParam("name", POKEMONS.get(2).getName()) - .execute(); - verifyPokemon(rows, POKEMONS.get(2)); - } - - /** - * Verify {@code createNamedQuery(String)} API method with ordered parameters. - */ - @Test - public void testCreateNamedQueryStrOrderArgs() { - Stream rows = dbClient.execute() - .createNamedQuery("select-pokemon-order-arg") - .addParam(POKEMONS.get(3).getName()) - .execute(); - verifyPokemon(rows, POKEMONS.get(3)); - } - - /** - * Verify {@code createQuery(String)} API method with named parameters. - */ - @Test - public void testCreateQueryNamedArgs() { - String stmt = config.get("db.statements.select-pokemon-named-arg").asString().get(); - Stream rows = dbClient.execute() - .createQuery(stmt) - .addParam("name", POKEMONS.get(4).getName()) - .execute(); - verifyPokemon(rows, POKEMONS.get(4)); - } - - /** - * Verify {@code createQuery(String)} API method with ordered parameters. - */ - @Test - public void testCreateQueryOrderArgs() { - String stmt = config.get("db.statements.select-pokemon-order-arg").asString().get(); - Stream rows = dbClient.execute() - .createQuery(stmt) - .addParam(POKEMONS.get(5).getName()) - .execute(); - verifyPokemon(rows, POKEMONS.get(5)); - } - - /** - * Verify {@code namedQuery(String)} API method with ordered parameters passed directly to the {@code namedQuery} method. - */ - @Test - public void testNamedQueryOrderArgs() { - Stream rows = dbClient.execute() - .namedQuery("select-pokemon-order-arg", POKEMONS.get(6).getName()); - verifyPokemon(rows, POKEMONS.get(6)); - } - - /** - * Verify {@code query(String)} API method with ordered parameters passed directly to the {@code query} method. - */ - @Test - public void testQueryOrderArgs() { - String stmt = config.get("db.statements.select-pokemon-order-arg").asString().get(); - Stream rows = dbClient.execute() - .query(stmt, POKEMONS.get(7).getName()); - verifyPokemon(rows, POKEMONS.get(7)); - } - -} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/SimpleUpdateIT.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/SimpleUpdateIT.java deleted file mode 100644 index 8e8f820a793..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/SimpleUpdateIT.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.tests.integration.dbclient.common.tests; - -import java.lang.System.Logger.Level; -import java.util.HashMap; -import java.util.Map; - -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.common.utils.TestConfig; - -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import static io.helidon.tests.integration.dbclient.common.model.Type.TYPES; -import static io.helidon.tests.integration.dbclient.common.utils.VerifyData.verifyInsertPokemon; -import static io.helidon.tests.integration.dbclient.common.utils.VerifyData.verifyUpdatePokemon; - -/** - * Test set of basic JDBC updates. - */ -@SuppressWarnings("SpellCheckingInspection") -@ExtendWith(DbClientParameterResolver.class) -public class SimpleUpdateIT { - - private static final System.Logger LOGGER = System.getLogger(SimpleUpdateIT.class.getName()); - private static final int BASE_ID = TestConfig.LAST_POKEMON_ID + 20; - private static final Map POKEMONS = new HashMap<>(); - - private final DbClient dbClient; - private final Config config; - - public SimpleUpdateIT(DbClient dbClient, Config config) { - this.dbClient = dbClient; - this.config = config; - } - - private static void addPokemon(DbClient dbClient, Pokemon pokemon) { - POKEMONS.put(pokemon.getId(), pokemon); - long result = dbClient.execute() - .namedInsert("insert-pokemon", pokemon.getId(), pokemon.getName()); - verifyInsertPokemon(dbClient, result, pokemon); - } - - /** - * Initialize tests of basic JDBC updates. - */ - @BeforeAll - public static void setup(DbClient dbClient) { - try { - int curId = BASE_ID; - addPokemon(dbClient, new Pokemon(++curId, "Spearow", TYPES.get(1), TYPES.get(3))); // BASE_ID+1 - addPokemon(dbClient, new Pokemon(++curId, "Fearow", TYPES.get(1), TYPES.get(3))); // BASE_ID+2 - addPokemon(dbClient, new Pokemon(++curId, "Ekans", TYPES.get(4))); // BASE_ID+3 - addPokemon(dbClient, new Pokemon(++curId, "Arbok", TYPES.get(4))); // BASE_ID+4 - addPokemon(dbClient, new Pokemon(++curId, "Sandshrew", TYPES.get(5))); // BASE_ID+5 - addPokemon(dbClient, new Pokemon(++curId, "Sandslash", TYPES.get(5))); // BASE_ID+6 - addPokemon(dbClient, new Pokemon(++curId, "Diglett", TYPES.get(5))); // BASE_ID+7 - } catch (Exception ex) { - LOGGER.log(Level.WARNING, String.format("Exception in setup: %s", ex)); - throw ex; - } - } - - /** - * Verify {@code createNamedUpdate(String, String)} API method with named parameters. - */ - @Test - public void testCreateNamedUpdateStrStrNamedArgs() { - Pokemon srcPokemon = POKEMONS.get(BASE_ID + 1); - Pokemon updatedPokemon = new Pokemon(BASE_ID + 1, "Fearow", srcPokemon.getTypesArray()); - String stmt = config.get("db.statements.update-pokemon-named-arg").asString().get(); - long result = dbClient.execute() - .createNamedUpdate("update-spearow", stmt) - .addParam("name", updatedPokemon.getName()).addParam("id", updatedPokemon.getId()) - .execute(); - verifyUpdatePokemon(dbClient, result, updatedPokemon); - } - - /** - * Verify {@code createNamedUpdate(String)} API method with named parameters. - */ - @Test - public void testCreateNamedUpdateStrNamedArgs() { - Pokemon srcPokemon = POKEMONS.get(BASE_ID + 2); - Pokemon updatedPokemon = new Pokemon(BASE_ID + 2, "Spearow", srcPokemon.getTypesArray()); - long result = dbClient.execute() - .createNamedUpdate("update-pokemon-named-arg") - .addParam("name", updatedPokemon.getName()).addParam("id", updatedPokemon.getId()) - .execute(); - verifyUpdatePokemon(dbClient, result, updatedPokemon); - } - - /** - * Verify {@code createNamedUpdate(String)} API method with ordered parameters. - */ - @Test - public void testCreateNamedUpdateStrOrderArgs() { - Pokemon srcPokemon = POKEMONS.get(BASE_ID + 3); - Pokemon updatedPokemon = new Pokemon(BASE_ID + 3, "Arbok", srcPokemon.getTypesArray()); - long result = dbClient.execute() - .createNamedUpdate("update-pokemon-order-arg") - .addParam(updatedPokemon.getName()).addParam(updatedPokemon.getId()) - .execute(); - verifyUpdatePokemon(dbClient, result, updatedPokemon); - } - - /** - * Verify {@code createUpdate(String)} API method with named parameters. - */ - @Test - public void testCreateUpdateNamedArgs() { - Pokemon srcPokemon = POKEMONS.get(BASE_ID + 4); - Pokemon updatedPokemon = new Pokemon(BASE_ID + 4, "Ekans", srcPokemon.getTypesArray()); - String stmt = config.get("db.statements.update-pokemon-named-arg").asString().get(); - long result = dbClient.execute() - .createUpdate(stmt) - .addParam("name", updatedPokemon.getName()).addParam("id", updatedPokemon.getId()) - .execute(); - verifyUpdatePokemon(dbClient, result, updatedPokemon); - } - - /** - * Verify {@code createUpdate(String)} API method with ordered parameters. - */ - @Test - public void testCreateUpdateOrderArgs() { - Pokemon srcPokemon = POKEMONS.get(BASE_ID + 5); - Pokemon updatedPokemon = new Pokemon(BASE_ID + 5, "Diglett", srcPokemon.getTypesArray()); - String stmt = config.get("db.statements.update-pokemon-order-arg").asString().get(); - long result = dbClient.execute() - .createUpdate(stmt) - .addParam(updatedPokemon.getName()).addParam(updatedPokemon.getId()) - .execute(); - verifyUpdatePokemon(dbClient, result, updatedPokemon); - } - - /** - * Verify {@code namedUpdate(String)} API method with named parameters. - */ - @Test - public void testNamedUpdateNamedArgs() { - Pokemon srcPokemon = POKEMONS.get(BASE_ID + 6); - Pokemon updatedPokemon = new Pokemon(BASE_ID + 6, "Sandshrew", srcPokemon.getTypesArray()); - long result = dbClient.execute() - .namedUpdate("update-pokemon-order-arg", updatedPokemon.getName(), updatedPokemon.getId()); - verifyUpdatePokemon(dbClient, result, updatedPokemon); - } - - /** - * Verify {@code update(String)} API method with ordered parameters. - */ - @Test - public void testUpdateOrderArgs() { - Pokemon srcPokemon = POKEMONS.get(BASE_ID + 7); - Pokemon updatedPokemon = new Pokemon(BASE_ID + 7, "Sandslash", srcPokemon.getTypesArray()); - String stmt = config.get("db.statements.update-pokemon-order-arg").asString().get(); - long result = dbClient.execute() - .update(stmt, updatedPokemon.getName(), updatedPokemon.getId()); - verifyUpdatePokemon(dbClient, result, updatedPokemon); - } -} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/StatementDmlIT.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/StatementDmlIT.java deleted file mode 100644 index d8cc1be2150..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/StatementDmlIT.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.tests.integration.dbclient.common.tests; - -import java.lang.System.Logger.Level; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import io.helidon.dbclient.DbClient; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.common.utils.TestConfig; - -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import static io.helidon.tests.integration.dbclient.common.model.Type.TYPES; -import static io.helidon.tests.integration.dbclient.common.utils.VerifyData.verifyInsertPokemon; -import static io.helidon.tests.integration.dbclient.common.utils.VerifyData.verifyUpdatePokemon; - -/** - * Test DbStatementDml methods. - */ -@SuppressWarnings("SpellCheckingInspection") -@ExtendWith(DbClientParameterResolver.class) -public class StatementDmlIT { - - private static final System.Logger LOGGER = System.getLogger(StatementDmlIT.class.getName()); - private static final int BASE_ID = TestConfig.LAST_POKEMON_ID + 100; - - private final DbClient dbClient; - - public StatementDmlIT(DbClient dbClient) { - this.dbClient = dbClient; - } - - private static void addPokemon(DbClient dbClient, Pokemon pokemon) { - long result = dbClient.execute() - .namedInsert("insert-pokemon", pokemon.getId(), pokemon.getName()); - verifyInsertPokemon(dbClient, result, pokemon); - } - - /** - * Initialize DbStatementDml methods tests. - */ - @BeforeAll - public static void setup(DbClient dbClient) { - try { - addPokemon(dbClient, new Pokemon(BASE_ID, "Shinx", TYPES.get(13))); // BASE_ID+0 - addPokemon(dbClient, new Pokemon(BASE_ID + 1, "Luxio", TYPES.get(13))); // BASE_ID+1 - addPokemon(dbClient, new Pokemon(BASE_ID + 2, "Luxray", TYPES.get(13))); // BASE_ID+2 - addPokemon(dbClient, new Pokemon(BASE_ID + 3, "Kricketot", TYPES.get(7))); // BASE_ID+3 - addPokemon(dbClient, new Pokemon(BASE_ID + 4, "Kricketune", TYPES.get(7))); // BASE_ID+4 - addPokemon(dbClient, new Pokemon(BASE_ID + 5, "Phione", TYPES.get(11))); // BASE_ID+5 - addPokemon(dbClient, new Pokemon(BASE_ID + 6, "Chatot", TYPES.get(1), TYPES.get(3))); // BASE_ID+6 - } catch (Exception ex) { - LOGGER.log(Level.WARNING, String.format("Exception in setup: %s", ex), ex); - throw ex; - } - } - - /** - * Verify {@code params(Object... parameters)} parameters setting method. - */ - @Test - public void testDmlArrayParams() { - Pokemon pokemon = new Pokemon(BASE_ID, "Luxio", TYPES.get(13)); - long result = dbClient.execute() - .createNamedDmlStatement("update-pokemon-order-arg") - .params(pokemon.getName(), pokemon.getId()) - .execute(); - verifyUpdatePokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code params(List)} parameters setting method. - */ - @Test - public void testDmlListParams() { - Pokemon pokemon = new Pokemon(BASE_ID + 1, "Luxray", TYPES.get(13)); - List params = new ArrayList<>(2); - params.add(pokemon.getName()); - params.add(pokemon.getId()); - long result = dbClient.execute() - .createNamedDmlStatement("update-pokemon-order-arg") - .params(params) - .execute(); - verifyUpdatePokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code params(Map)} parameters setting method. - */ - @Test - public void testDmlMapParams() { - Pokemon pokemon = new Pokemon(BASE_ID + 2, "Shinx", TYPES.get(13)); - Map params = new HashMap<>(2); - params.put("name", pokemon.getName()); - params.put("id", pokemon.getId()); - long result = dbClient.execute() - .createNamedDmlStatement("update-pokemon-named-arg") - .params(params) - .execute(); - verifyUpdatePokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code addParam(Object parameter)} parameters setting method. - */ - @Test - public void testDmlOrderParam() { - Pokemon pokemon = new Pokemon(BASE_ID + 3, "Kricketune", TYPES.get(7)); - long result = dbClient.execute() - .createNamedDmlStatement("update-pokemon-order-arg") - .addParam(pokemon.getName()) - .addParam(pokemon.getId()) - .execute(); - verifyUpdatePokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code addParam(String name, Object parameter)} parameters setting method. - */ - @Test - public void testDmlNamedParam() { - Pokemon pokemon = new Pokemon(BASE_ID + 4, "Kricketot", TYPES.get(7)); - long result = dbClient.execute() - .createNamedDmlStatement("update-pokemon-named-arg") - .addParam("name", pokemon.getName()) - .addParam("id", pokemon.getId()) - .execute(); - verifyUpdatePokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code namedParam(Object parameters)} mapped parameters setting method. - */ - @Test - public void testDmlMappedNamedParam() { - Pokemon pokemon = new Pokemon(BASE_ID + 5, "Chatot", TYPES.get(1), TYPES.get(3)); - long result = dbClient.execute() - .createNamedDmlStatement("update-pokemon-named-arg") - .namedParam(pokemon) - .execute(); - verifyUpdatePokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code indexedParam(Object parameters)} mapped parameters setting method. - */ - @Test - public void testDmlMappedOrderParam() { - Pokemon pokemon = new Pokemon(BASE_ID + 6, "Phione", TYPES.get(11)); - long result = dbClient.execute() - .createNamedDmlStatement("update-pokemon-order-arg") - .indexedParam(pokemon) - .execute(); - verifyUpdatePokemon(dbClient, result, pokemon); - } -} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/TransactionDeleteIT.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/TransactionDeleteIT.java deleted file mode 100644 index 0a3203142ef..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/TransactionDeleteIT.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.tests.integration.dbclient.common.tests; - -import java.lang.System.Logger.Level; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ExecutionException; - -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbTransaction; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.common.utils.TestConfig; - -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import static io.helidon.tests.integration.dbclient.common.model.Type.TYPES; -import static io.helidon.tests.integration.dbclient.common.utils.VerifyData.verifyDeletePokemon; -import static io.helidon.tests.integration.dbclient.common.utils.VerifyData.verifyInsertPokemon; - -/** - * Test set of basic JDBC delete calls in transaction. - */ -@SuppressWarnings("SpellCheckingInspection") -@ExtendWith(DbClientParameterResolver.class) -public class TransactionDeleteIT { - - private static final System.Logger LOGGER = System.getLogger(TransactionDeleteIT.class.getName()); - private static final int BASE_ID = TestConfig.LAST_POKEMON_ID + 230; - private static final Map POKEMONS = new HashMap<>(); - - private final DbClient dbClient; - private final Config config; - - public TransactionDeleteIT(DbClient dbClient, Config config) { - this.dbClient = dbClient; - this.config = config; - } - - private static void addPokemon(DbClient dbClient, Pokemon pokemon) { - POKEMONS.put(pokemon.getId(), pokemon); - long result = dbClient.execute() - .namedInsert("insert-pokemon", pokemon.getId(), pokemon.getName()); - verifyInsertPokemon(dbClient, result, pokemon); - } - - @BeforeAll - public static void setup(DbClient dbClient) throws ExecutionException, InterruptedException { - try { - int curId = BASE_ID; - addPokemon(dbClient, new Pokemon(++curId, "Omanyte", TYPES.get(6), TYPES.get(11))); // BASE_ID+1 - addPokemon(dbClient, new Pokemon(++curId, "Omastar", TYPES.get(6), TYPES.get(11))); // BASE_ID+2 - addPokemon(dbClient, new Pokemon(++curId, "Kabuto", TYPES.get(6), TYPES.get(11))); // BASE_ID+3 - addPokemon(dbClient, new Pokemon(++curId, "Kabutops", TYPES.get(6), TYPES.get(11))); // BASE_ID+4 - addPokemon(dbClient, new Pokemon(++curId, "Chikorita", TYPES.get(12))); // BASE_ID+5 - addPokemon(dbClient, new Pokemon(++curId, "Bayleef", TYPES.get(12))); // BASE_ID+6 - addPokemon(dbClient, new Pokemon(++curId, "Meganium", TYPES.get(12))); // BASE_ID+7 - } catch (Exception ex) { - LOGGER.log(Level.WARNING, String.format("Exception in setup: %s", ex)); - throw ex; - } - } - - /** - * Verify {@code createNamedDelete(String, String)} API method with ordered parameters. - */ - @Test - public void testCreateNamedDeleteStrStrOrderArgs() { - Pokemon pokemon = POKEMONS.get(BASE_ID + 1); - String stmt = config.get("db.statements.delete-pokemon-order-arg").asString().get(); - DbTransaction tx = dbClient.transaction(); - long result = tx - .createNamedDelete("delete-rayquaza", stmt) - .addParam(pokemon.getId()) - .execute(); - tx.commit(); - verifyDeletePokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code createNamedDelete(String)} API method with named parameters. - */ - @Test - public void testCreateNamedDeleteStrNamedArgs() { - Pokemon pokemon = POKEMONS.get(BASE_ID + 2); - DbTransaction tx = dbClient.transaction(); - long result = tx - .createNamedDelete("delete-pokemon-named-arg") - .addParam("id", pokemon.getId()) - .execute(); - tx.commit(); - verifyDeletePokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code createNamedDelete(String)} API method with ordered parameters. - */ - @Test - public void testCreateNamedDeleteStrOrderArgs() { - Pokemon pokemon = POKEMONS.get(BASE_ID + 3); - DbTransaction tx = dbClient.transaction(); - long result = tx - .createNamedDelete("delete-pokemon-order-arg") - .addParam(pokemon.getId()) - .execute(); - tx.commit(); - verifyDeletePokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code createDelete(String)} API method with named parameters. - */ - @Test - public void testCreateDeleteNamedArgs() { - Pokemon pokemon = POKEMONS.get(BASE_ID + 4); - String stmt = config.get("db.statements.delete-pokemon-named-arg").asString().get(); - DbTransaction tx = dbClient.transaction(); - long result = tx - .createDelete(stmt) - .addParam("id", pokemon.getId()) - .execute(); - tx.commit(); - verifyDeletePokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code createDelete(String)} API method with ordered parameters. - */ - @Test - public void testCreateDeleteOrderArgs() { - Pokemon pokemon = POKEMONS.get(BASE_ID + 5); - String stmt = config.get("db.statements.delete-pokemon-order-arg").asString().get(); - DbTransaction tx = dbClient.transaction(); - long result = tx - .createDelete(stmt) - .addParam(pokemon.getId()) - .execute(); - tx.commit(); - verifyDeletePokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code namedDelete(String)} API method with ordered parameters. - */ - @Test - public void testNamedDeleteOrderArgs() { - Pokemon pokemon = POKEMONS.get(BASE_ID + 6); - DbTransaction tx = dbClient.transaction(); - long result = tx - .namedDelete("delete-pokemon-order-arg", pokemon.getId()); - tx.commit(); - verifyDeletePokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code delete(String)} API method with ordered parameters. - */ - @Test - public void testDeleteOrderArgs() { - Pokemon pokemon = POKEMONS.get(BASE_ID + 7); - String stmt = config.get("db.statements.delete-pokemon-order-arg").asString().get(); - DbTransaction tx = dbClient.transaction(); - long result = tx - .delete(stmt, pokemon.getId()); - tx.commit(); - verifyDeletePokemon(dbClient, result, pokemon); - } -} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/TransactionExceptionalStmtIT.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/TransactionExceptionalStmtIT.java deleted file mode 100644 index f32eac068e2..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/TransactionExceptionalStmtIT.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.tests.integration.dbclient.common.tests; - -import java.lang.System.Logger.Level; -import java.util.concurrent.CompletionException; - -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbClientException; -import io.helidon.dbclient.DbTransaction; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import static io.helidon.tests.integration.dbclient.common.model.Pokemon.POKEMONS; -import static org.junit.jupiter.api.Assertions.fail; - -/** - * Test exceptional states. - */ -@ExtendWith(DbClientParameterResolver.class) -public class TransactionExceptionalStmtIT { - - private static final System.Logger LOGGER = System.getLogger(TransactionExceptionalStmtIT.class.getName()); - - private final DbClient dbClient; - - public TransactionExceptionalStmtIT(DbClient dbClient) { - this.dbClient = dbClient; - } - - /** - * Verify that execution of query with non-existing named statement throws an exception. - */ - @Test - public void testCreateNamedQueryNonExistentStmt() { - try { - DbTransaction tx = dbClient.transaction(); - tx.createNamedQuery("select-pokemons-not-exists") - .execute() - .forEach(it -> {}); - tx.commit(); - fail("Execution of non existing statement shall cause an exception to be thrown."); - } catch (DbClientException ex) { - LOGGER.log(Level.DEBUG, () -> String.format("Expected exception: %s", ex.getMessage()), ex); - } - } - - /** - * Verify that execution of query with both named and ordered arguments throws an exception. - */ - @Test - public void testCreateNamedQueryNamedAndOrderArgsWithoutArgs() { - try { - DbTransaction tx = dbClient.transaction(); - tx.createNamedQuery("select-pokemons-error-arg") - .execute() - .forEach(it -> {}); - tx.commit(); - fail("Execution of query with both named and ordered parameters without passing any shall fail."); - } catch (DbClientException | - CompletionException ex) { - LOGGER.log(Level.DEBUG, () -> String.format("Expected exception: %s", ex.getMessage()), ex); - } - } - - /** - * Verify that execution of query with both named and ordered arguments throws an exception. - */ - @Test - public void testCreateNamedQueryNamedAndOrderArgsWithArgs() { - try { - DbTransaction tx = dbClient.transaction(); - tx.createNamedQuery("select-pokemons-error-arg") - .addParam("id", POKEMONS.get(5).getId()) - .addParam(POKEMONS.get(5).getName()) - .execute() - .forEach(it -> {}); - tx.commit(); - fail("Execution of query with both named and ordered parameters without passing them shall fail."); - } catch (DbClientException ex) { - LOGGER.log(Level.DEBUG, () -> String.format("Expected exception: %s", ex.getMessage()), ex); - } - } - - /** - * Verify that execution of query with named arguments throws an exception while trying to set ordered argument. - */ - @Test - public void testCreateNamedQueryNamedArgsSetOrderArg() { - try { - DbTransaction tx = dbClient.transaction(); - tx.createNamedQuery("select-pokemon-named-arg") - .addParam(POKEMONS.get(5).getName()) - .execute() - .forEach(it -> {}); - tx.commit(); - fail("Execution of query with named parameter with passing ordered parameter value shall fail."); - } catch (DbClientException ex) { - LOGGER.log(Level.DEBUG, () -> String.format("Expected exception: %s", ex.getMessage()), ex); - } - } - - /** - * Verify that execution of query with ordered arguments throws an exception while trying to set named argument. - */ - @Test - public void testCreateNamedQueryOrderArgsSetNamedArg() { - try { - DbTransaction tx = dbClient.transaction(); - tx.createNamedQuery("select-pokemon-order-arg") - .addParam("name", POKEMONS.get(6).getName()) - .execute() - .forEach(it -> {}); - tx.commit(); - fail("Execution of query with ordered parameter with passing named parameter value shall fail."); - } catch (DbClientException ex) { - LOGGER.log(Level.DEBUG, () -> String.format("Expected exception: %s", ex.getMessage()), ex); - } - } -} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/TransactionGetIT.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/TransactionGetIT.java deleted file mode 100644 index 43e4e7ae108..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/TransactionGetIT.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.tests.integration.dbclient.common.tests; - -import java.util.Optional; - -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbRow; -import io.helidon.dbclient.DbTransaction; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import static io.helidon.tests.integration.dbclient.common.model.Pokemon.POKEMONS; -import static io.helidon.tests.integration.dbclient.common.utils.VerifyData.verifyPokemon; - -/** - * Test set of basic JDBC get calls in transaction. - */ -@ExtendWith(DbClientParameterResolver.class) -public class TransactionGetIT { - - private final DbClient dbClient; - private final Config config; - - public TransactionGetIT(DbClient dbClient, Config config) { - this.dbClient = dbClient; - this.config = config; - } - - /** - * Verify {@code createNamedGet(String, String)} API method with named parameters. - */ - @Test - public void testCreateNamedGetStrStrNamedArgs() { - String stmt = config.get("db.statements.select-pokemon-named-arg").asString().get(); - DbTransaction tx = dbClient.transaction(); - Optional maybeRow = tx - .createNamedGet("select-pikachu", stmt) - .addParam("name", POKEMONS.get(1).getName()) - .execute(); - tx.commit(); - verifyPokemon(maybeRow, POKEMONS.get(1)); - } - - /** - * Verify {@code createNamedGet(String)} API method with named parameters. - */ - @Test - public void testCreateNamedGetStrNamedArgs() { - DbTransaction tx = dbClient.transaction(); - Optional maybeRow = tx - .createNamedGet("select-pokemon-named-arg") - .addParam("name", POKEMONS.get(2).getName()) - .execute(); - tx.commit(); - - verifyPokemon(maybeRow, POKEMONS.get(2)); - } - - /** - * Verify {@code createNamedGet(String)} API method with ordered parameters. - */ - @Test - public void testCreateNamedGetStrOrderArgs() { - DbTransaction tx = dbClient.transaction(); - Optional maybeRow = tx - .createNamedGet("select-pokemon-order-arg") - .addParam(POKEMONS.get(3).getName()) - .execute(); - tx.commit(); - - verifyPokemon(maybeRow, POKEMONS.get(3)); - } - - /** - * Verify {@code createGet(String)} API method with named parameters. - */ - @Test - public void testCreateGetNamedArgs() { - String stmt = config.get("db.statements.select-pokemon-named-arg").asString().get(); - DbTransaction tx = dbClient.transaction(); - Optional maybeRow = tx - .createGet(stmt) - .addParam("name", POKEMONS.get(4).getName()) - .execute(); - tx.commit(); - - verifyPokemon(maybeRow, POKEMONS.get(4)); - } - - /** - * Verify {@code createGet(String)} API method with ordered parameters. - */ - @Test - public void testCreateGetOrderArgs() { - String stmt = config.get("db.statements.select-pokemon-order-arg").asString().get(); - DbTransaction tx = dbClient.transaction(); - Optional maybeRow = tx - .createGet(stmt) - .addParam(POKEMONS.get(5).getName()) - .execute(); - tx.commit(); - - verifyPokemon(maybeRow, POKEMONS.get(5)); - } - - /** - * Verify {@code namedGet(String)} API method with ordered parameters passed directly to the {@code query} method. - */ - @Test - public void testNamedGetStrOrderArgs() { - DbTransaction tx = dbClient.transaction(); - Optional maybeRow = tx - .namedGet("select-pokemon-order-arg", POKEMONS.get(6).getName()); - tx.commit(); - - verifyPokemon(maybeRow, POKEMONS.get(6)); - } - - /** - * Verify {@code get(String)} API method with ordered parameters passed directly to the {@code query} method. - */ - @Test - public void testGetStrOrderArgs() { - String stmt = config.get("db.statements.select-pokemon-order-arg").asString().get(); - DbTransaction tx = dbClient.transaction(); - Optional maybeRow = tx - .get(stmt, POKEMONS.get(7).getName()); - tx.commit(); - - verifyPokemon(maybeRow, POKEMONS.get(7)); - } -} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/TransactionInsertIT.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/TransactionInsertIT.java deleted file mode 100644 index a8d19199f40..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/TransactionInsertIT.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.tests.integration.dbclient.common.tests; - -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbTransaction; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.common.utils.TestConfig; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import static io.helidon.tests.integration.dbclient.common.model.Type.TYPES; -import static io.helidon.tests.integration.dbclient.common.utils.VerifyData.verifyInsertPokemon; - -/** - * Test set of basic JDBC inserts in transaction. - */ -@SuppressWarnings("SpellCheckingInspection") -@ExtendWith(DbClientParameterResolver.class) -public class TransactionInsertIT { - - private static final int BASE_ID = TestConfig.LAST_POKEMON_ID + 210; - - private final DbClient dbClient; - private final Config config; - - public TransactionInsertIT(DbClient dbClient, Config config) { - this.dbClient = dbClient; - this.config = config; - } - - /** - * Verify {@code createNamedInsert(String, String)} API method with named parameters. - */ - @Test - public void testCreateNamedInsertStrStrNamedArgs() { - Pokemon pokemon = new Pokemon(BASE_ID + 1, "Sentret", TYPES.get(1)); - String stmt = config.get("db.statements.insert-pokemon-named-arg").asString().get(); - DbTransaction tx = dbClient.transaction(); - long result = tx - .createNamedInsert("insert-bulbasaur", stmt) - .addParam("id", pokemon.getId()).addParam("name", pokemon.getName()).execute(); - tx.commit(); - verifyInsertPokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code createNamedInsert(String)} API method with named parameters. - */ - @Test - public void testCreateNamedInsertStrNamedArgs() { - Pokemon pokemon = new Pokemon(BASE_ID + 2, "Furret", TYPES.get(1)); - DbTransaction tx = dbClient.transaction(); - long result = tx - .createNamedInsert("insert-pokemon-named-arg") - .addParam("id", pokemon.getId()).addParam("name", pokemon.getName()).execute(); - tx.commit(); - verifyInsertPokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code createNamedInsert(String)} API method with ordered parameters. - */ - @Test - public void testCreateNamedInsertStrOrderArgs() { - Pokemon pokemon = new Pokemon(BASE_ID + 3, "Chinchou", TYPES.get(11), TYPES.get(13)); - DbTransaction tx = dbClient.transaction(); - long result = tx - .createNamedInsert("insert-pokemon-order-arg") - .addParam(pokemon.getId()).addParam(pokemon.getName()).execute(); - tx.commit(); - verifyInsertPokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code createInsert(String)} API method with named parameters. - */ - @Test - public void testCreateInsertNamedArgs() { - Pokemon pokemon = new Pokemon(BASE_ID + 4, "Lanturn", TYPES.get(11), TYPES.get(13)); - String stmt = config.get("db.statements.insert-pokemon-named-arg").asString().get(); - DbTransaction tx = dbClient.transaction(); - long result = tx - .createInsert(stmt) - .addParam("id", pokemon.getId()).addParam("name", pokemon.getName()).execute(); - tx.commit(); - verifyInsertPokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code createInsert(String)} API method with ordered parameters. - */ - @Test - public void testCreateInsertOrderArgs() { - Pokemon pokemon = new Pokemon(BASE_ID + 5, "Swinub", TYPES.get(5), TYPES.get(15)); - String stmt = config.get("db.statements.insert-pokemon-order-arg").asString().get(); - DbTransaction tx = dbClient.transaction(); - long result = tx - .createInsert(stmt) - .addParam(pokemon.getId()).addParam(pokemon.getName()).execute(); - tx.commit(); - verifyInsertPokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code namedInsert(String)} API method with ordered parameters passed directly to the {@code insert} method. - */ - @Test - public void testNamedInsertOrderArgs() { - Pokemon pokemon = new Pokemon(BASE_ID + 6, "Piloswine", TYPES.get(5), TYPES.get(15)); - DbTransaction tx = dbClient.transaction(); - long result = tx - .namedInsert("insert-pokemon-order-arg", pokemon.getId(), pokemon.getName()); - tx.commit(); - verifyInsertPokemon(dbClient, result, pokemon); - } - - /** - * Verify {@code insert(String)} API method with ordered parameters passed directly to the {@code insert} method. - */ - @Test - public void testInsertOrderArgs() { - Pokemon pokemon = new Pokemon(BASE_ID + 7, "Mamoswine", TYPES.get(5), TYPES.get(15)); - String stmt = config.get("db.statements.insert-pokemon-order-arg").asString().get(); - DbTransaction tx = dbClient.transaction(); - long result = tx - .insert(stmt, pokemon.getId(), pokemon.getName()); - tx.commit(); - verifyInsertPokemon(dbClient, result, pokemon); - } -} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/TransactionQueriesIT.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/TransactionQueriesIT.java deleted file mode 100644 index aba3a98e987..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/TransactionQueriesIT.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.tests.integration.dbclient.common.tests; - -import java.util.List; - -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbRow; -import io.helidon.dbclient.DbTransaction; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import static io.helidon.tests.integration.dbclient.common.model.Pokemon.POKEMONS; -import static io.helidon.tests.integration.dbclient.common.utils.VerifyData.verifyPokemon; - -/** - * Test set of basic JDBC queries in transaction. - */ -@ExtendWith(DbClientParameterResolver.class) -public class TransactionQueriesIT { - - private final DbClient dbClient; - private final Config config; - - public TransactionQueriesIT(DbClient dbClient, Config config) { - this.dbClient = dbClient; - this.config = config; - } - - /** - * Verify {@code createNamedQuery(String, String)} API method with ordered parameters. - */ - @Test - public void testCreateNamedQueryStrStrOrderArgs() { - String stmt = config.get("db.statements.select-pokemon-order-arg").asString().get(); - DbTransaction tx = dbClient.transaction(); - List rows = tx - .createNamedQuery("select-pikachu", stmt) - .addParam(POKEMONS.get(1).getName()) - .execute() - .toList(); - tx.commit(); - verifyPokemon(rows, POKEMONS.get(1)); - } - - /** - * Verify {@code createNamedQuery(String)} API method with named parameters. - */ - @Test - public void testCreateNamedQueryStrNamedArgs() { - DbTransaction tx = dbClient.transaction(); - List rows = tx - .createNamedQuery("select-pokemon-named-arg") - .addParam("name", POKEMONS.get(2).getName()) - .execute() - .toList(); - tx.commit(); - verifyPokemon(rows, POKEMONS.get(2)); - } - - /** - * Verify {@code createNamedQuery(String)} API method with ordered parameters. - */ - @Test - public void testCreateNamedQueryStrOrderArgs() { - DbTransaction tx = dbClient.transaction(); - List rows = tx - .createNamedQuery("select-pokemon-order-arg") - .addParam(POKEMONS.get(3).getName()) - .execute() - .toList(); - tx.commit(); - verifyPokemon(rows, POKEMONS.get(3)); - } - - /** - * Verify {@code createQuery(String)} API method with named parameters. - */ - @Test - public void testCreateQueryNamedArgs() { - String stmt = config.get("db.statements.select-pokemon-named-arg").asString().get(); - DbTransaction tx = dbClient.transaction(); - List rows = tx - .createQuery(stmt) - .addParam("name", POKEMONS.get(4).getName()) - .execute() - .toList(); - tx.commit(); - verifyPokemon(rows, POKEMONS.get(4)); - } - - /** - * Verify {@code createQuery(String)} API method with ordered parameters. - */ - @Test - public void testCreateQueryOrderArgs() { - String stmt = config.get("db.statements.select-pokemon-order-arg").asString().get(); - DbTransaction tx = dbClient.transaction(); - List rows = tx - .createQuery(stmt) - .addParam(POKEMONS.get(5).getName()) - .execute() - .toList(); - tx.commit(); - verifyPokemon(rows, POKEMONS.get(5)); - } - - /** - * Verify {@code namedQuery(String)} API method with ordered parameters passed directly to the {@code namedQuery} method. - */ - @Test - public void testNamedQueryOrderArgs() { - DbTransaction tx = dbClient.transaction(); - List rows = tx - .namedQuery("select-pokemon-order-arg", POKEMONS.get(6).getName()) - .toList(); - tx.commit(); - verifyPokemon(rows, POKEMONS.get(6)); - } - - /** - * Verify {@code query(String)} API method with ordered parameters passed directly to the {@code query} method. - */ - @Test - public void testQueryOrderArgs() { - String stmt = config.get("db.statements.select-pokemon-order-arg").asString().get(); - DbTransaction tx = dbClient.transaction(); - List rows = tx - .query(stmt, POKEMONS.get(7).getName()) - .toList(); - tx.commit(); - verifyPokemon(rows, POKEMONS.get(7)); - } -} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/TransactionUpdateIT.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/TransactionUpdateIT.java deleted file mode 100644 index c39f3a57910..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/tests/TransactionUpdateIT.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.tests.integration.dbclient.common.tests; - -import java.lang.System.Logger.Level; -import java.util.HashMap; -import java.util.Map; - -import io.helidon.config.Config; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbTransaction; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.common.utils.TestConfig; - -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import static io.helidon.tests.integration.dbclient.common.model.Type.TYPES; -import static io.helidon.tests.integration.dbclient.common.utils.VerifyData.verifyInsertPokemon; -import static io.helidon.tests.integration.dbclient.common.utils.VerifyData.verifyUpdatePokemon; - -/** - * Test set of basic JDBC updates in transaction. - */ -@SuppressWarnings("SpellCheckingInspection") -@ExtendWith(DbClientParameterResolver.class) -public class TransactionUpdateIT { - - private static final System.Logger LOGGER = System.getLogger(TransactionUpdateIT.class.getName()); - private static final int BASE_ID = TestConfig.LAST_POKEMON_ID + 220; - private static final Map POKEMONS = new HashMap<>(); - - private final DbClient dbClient; - private final Config config; - - public TransactionUpdateIT(DbClient dbClient, Config config) { - this.dbClient = dbClient; - this.config = config; - } - - private static void addPokemon(DbClient dbClient, Pokemon pokemon) { - POKEMONS.put(pokemon.getId(), pokemon); - long result = dbClient.execute() - .namedInsert("insert-pokemon", pokemon.getId(), pokemon.getName()); - verifyInsertPokemon(dbClient, result, pokemon); - } - - @BeforeAll - public static void setup(DbClient dbClient) { - try { - int curId = BASE_ID; - addPokemon(dbClient, new Pokemon(++curId, "Teddiursa", TYPES.get(1))); // BASE_ID+1 - addPokemon(dbClient, new Pokemon(++curId, "Ursaring", TYPES.get(1))); // BASE_ID+2 - addPokemon(dbClient, new Pokemon(++curId, "Slugma", TYPES.get(10))); // BASE_ID+3 - addPokemon(dbClient, new Pokemon(++curId, "Magcargo", TYPES.get(6), TYPES.get(10))); // BASE_ID+4 - addPokemon(dbClient, new Pokemon(++curId, "Lotad", TYPES.get(11), TYPES.get(12))); // BASE_ID+5 - addPokemon(dbClient, new Pokemon(++curId, "Lombre", TYPES.get(11), TYPES.get(12))); // BASE_ID+6 - addPokemon(dbClient, new Pokemon(++curId, "Ludicolo", TYPES.get(11), TYPES.get(12))); // BASE_ID+7 - } catch (Exception ex) { - LOGGER.log(Level.WARNING, String.format("Exception in setup: %s", ex)); - throw ex; - } - } - - /** - * Verify {@code createNamedUpdate(String, String)} API method with named parameters. - */ - @Test - public void testCreateNamedUpdateStrStrNamedArgs() { - Pokemon srcPokemon = POKEMONS.get(BASE_ID + 1); - Pokemon updatedPokemon = new Pokemon(BASE_ID + 1, "Ursaring", srcPokemon.getTypesArray()); - String stmt = config.get("db.statements.update-pokemon-named-arg").asString().get(); - DbTransaction tx = dbClient.transaction(); - long result = tx - .createNamedUpdate("update-spearow", stmt) - .addParam("name", updatedPokemon.getName()).addParam("id", updatedPokemon.getId()) - .execute(); - tx.commit(); - verifyUpdatePokemon(dbClient, result, updatedPokemon); - } - - /** - * Verify {@code createNamedUpdate(String)} API method with named parameters. - */ - @Test - public void testCreateNamedUpdateStrNamedArgs() { - Pokemon srcPokemon = POKEMONS.get(BASE_ID + 2); - Pokemon updatedPokemon = new Pokemon(BASE_ID + 2, "Teddiursa", srcPokemon.getTypesArray()); - DbTransaction tx = dbClient.transaction(); - long result = tx - .createNamedUpdate("update-pokemon-named-arg") - .addParam("name", updatedPokemon.getName()).addParam("id", updatedPokemon.getId()) - .execute(); - tx.commit(); - verifyUpdatePokemon(dbClient, result, updatedPokemon); - } - - /** - * Verify {@code createNamedUpdate(String)} API method with ordered parameters. - */ - @Test - public void testCreateNamedUpdateStrOrderArgs() { - Pokemon srcPokemon = POKEMONS.get(BASE_ID + 3); - Pokemon updatedPokemon = new Pokemon(BASE_ID + 3, "Magcargo", srcPokemon.getTypesArray()); - DbTransaction tx = dbClient.transaction(); - long result = tx - .createNamedUpdate("update-pokemon-order-arg") - .addParam(updatedPokemon.getName()).addParam(updatedPokemon.getId()) - .execute(); - tx.commit(); - verifyUpdatePokemon(dbClient, result, updatedPokemon); - } - - /** - * Verify {@code createUpdate(String)} API method with named parameters. - */ - @Test - public void testCreateUpdateNamedArgs() { - Pokemon srcPokemon = POKEMONS.get(BASE_ID + 4); - Pokemon updatedPokemon = new Pokemon(BASE_ID + 4, "Slugma", srcPokemon.getTypesArray()); - String stmt = config.get("db.statements.update-pokemon-named-arg").asString().get(); - DbTransaction tx = dbClient.transaction(); - long result = tx - .createUpdate(stmt) - .addParam("name", updatedPokemon.getName()).addParam("id", updatedPokemon.getId()) - .execute(); - tx.commit(); - verifyUpdatePokemon(dbClient, result, updatedPokemon); - } - - /** - * Verify {@code createUpdate(String)} API method with ordered parameters. - */ - @Test - public void testCreateUpdateOrderArgs() { - Pokemon srcPokemon = POKEMONS.get(BASE_ID + 5); - Pokemon updatedPokemon = new Pokemon(BASE_ID + 5, "Lombre", srcPokemon.getTypesArray()); - String stmt = config.get("db.statements.update-pokemon-order-arg").asString().get(); - DbTransaction tx = dbClient.transaction(); - long result = tx - .createUpdate(stmt) - .addParam(updatedPokemon.getName()).addParam(updatedPokemon.getId()) - .execute(); - tx.commit(); - verifyUpdatePokemon(dbClient, result, updatedPokemon); - } - - /** - * Verify {@code namedUpdate(String)} API method with named parameters. - */ - @Test - public void testNamedUpdateNamedArgs() { - Pokemon srcPokemon = POKEMONS.get(BASE_ID + 6); - Pokemon updatedPokemon = new Pokemon(BASE_ID + 6, "Ludicolo", srcPokemon.getTypesArray()); - DbTransaction tx = dbClient.transaction(); - long result = tx - .namedUpdate("update-pokemon-order-arg", updatedPokemon.getName(), updatedPokemon.getId()); - tx.commit(); - verifyUpdatePokemon(dbClient, result, updatedPokemon); - } - - /** - * Verify {@code update(String)} API method with ordered parameters. - */ - @Test - public void testUpdateOrderArgs() { - Pokemon srcPokemon = POKEMONS.get(BASE_ID + 7); - Pokemon updatedPokemon = new Pokemon(BASE_ID + 7, "Lotad", srcPokemon.getTypesArray()); - String stmt = config.get("db.statements.update-pokemon-order-arg").asString().get(); - DbTransaction tx = dbClient.transaction(); - long result = tx - .update(stmt, updatedPokemon.getName(), updatedPokemon.getId()); - tx.commit(); - verifyUpdatePokemon(dbClient, result, updatedPokemon); - } -} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/utils/MapperProvider.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/utils/MapperProvider.java deleted file mode 100644 index 53dd69928f9..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/utils/MapperProvider.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.tests.integration.dbclient.common.utils; - -import java.util.Optional; - -import io.helidon.dbclient.DbMapper; -import io.helidon.dbclient.spi.DbMapperProvider; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.common.model.Pokemon.PokemonMapper; - -/** - * Mapper provider used in integration tests. - */ -public class MapperProvider implements DbMapperProvider { - - @Override - @SuppressWarnings("unchecked") - public Optional> mapper(Class type) { - if (type.equals(RangePoJo.class)) { - return Optional.of((DbMapper) RangePoJo.Mapper.INSTANCE); - } else if (type.equals(Pokemon.class)) { - return Optional.of((DbMapper) PokemonMapper.INSTANCE); - } - return Optional.empty(); - } -} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/utils/RangePoJo.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/utils/RangePoJo.java deleted file mode 100644 index 9812440fef6..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/utils/RangePoJo.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.tests.integration.dbclient.common.utils; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import io.helidon.dbclient.DbMapper; -import io.helidon.dbclient.DbRow; - -/** - * POJO used to define {@code Pokemon} IDs range in query statement tests. - */ -public class RangePoJo { - - public static final class Mapper implements DbMapper { - - public static final Mapper INSTANCE = new Mapper(); - - @Override - public RangePoJo read(DbRow row) { - throw new UnsupportedOperationException("Read operation is not implemented."); - } - - @Override - public Map toNamedParameters(RangePoJo value) { - Map params = new HashMap<>(2); - params.put("idmin", value.getIdMin()); - params.put("idmax", value.getIdMax()); - return params; - } - - @Override - public List toIndexedParameters(RangePoJo value) { - List params = new ArrayList<>(2); - params.add(value.getIdMin()); - params.add(value.getIdMax()); - return params; - } - - } - - /** Beginning of IDs range. */ - private final int idMin; - /** End of IDs range. */ - private final int idMax; - - /** - * Creates an instance of Range POJO. - * - * @param idMin beginning of IDs range - * @param idMax end of IDs range - */ - public RangePoJo(int idMin, int idMax) { - this.idMin = idMin; - this.idMax = idMax; - } - - /** - * Get beginning of IDs range. - * - * @return beginning of IDs range - */ - public int getIdMin() { - return idMin; - } - - /** - * Get end of IDs range. - * - * @return end of IDs range - */ - public int getIdMax() { - return idMax; - } - -} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/utils/TestConfig.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/utils/TestConfig.java deleted file mode 100644 index 55315375cbf..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/utils/TestConfig.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.tests.integration.dbclient.common.utils; - -import java.lang.System.Logger.Level; - -/** - * Configuration utilities. - */ -public class TestConfig { - - /** Last used id in {@code Pokemon} table. */ - public static final int LAST_POKEMON_ID = 1000; - - private static final System.Logger LOGGER = System.getLogger(TestConfig.class.getName()); - private static final String CONFIG_PROPERTY_NAME = "io.helidon.tests.integration.dbclient.config"; - private static final String DEFAULT_CONFIG_FILE = "test.yaml"; - - /** - * Retrieve configuration file from {@code io.helidon.tests.integration.dbclient.config} - * property if exists. - * Default {@code test.yaml} value is used when no property is set. - * - * @return tests configuration file name - */ - public static String configFile() { - String configFile = System.getProperty(CONFIG_PROPERTY_NAME, DEFAULT_CONFIG_FILE); - LOGGER.log(Level.DEBUG, () -> String.format("Configuration file: %s", configFile)); - return configFile; - } - -} diff --git a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/utils/VerifyData.java b/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/utils/VerifyData.java deleted file mode 100644 index 31f0c19ec71..00000000000 --- a/tests/integration/dbclient/common/src/main/java/io/helidon/tests/integration/dbclient/common/utils/VerifyData.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) 2019, 2023 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.tests.integration.dbclient.common.utils; - -import java.lang.System.Logger.Level; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Stream; - -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbRow; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; - -import static io.helidon.tests.integration.dbclient.common.model.Pokemon.POKEMONS; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.notNullValue; - -/** - * Test utilities. - */ -public class VerifyData { - - private static final System.Logger LOGGER = System.getLogger(VerifyData.class.getName()); - - private VerifyData() { - } - - /** - * Verify that the given rows contain data matching specified IDs range. - * - * @param rows database query result to verify - * @param idMin beginning of ID range - * @param idMax end of ID range - */ - public static void verifyPokemonsIdRange(Stream rows, int idMin, int idMax) { - // Build Map of valid data - Map valid = range(idMin, idMax); - - // Compare result with valid data - assertThat(rows, notNullValue()); - List rowsList = rows.toList(); - assertThat(rowsList, hasSize(valid.size())); - for (DbRow row : rowsList) { - Integer id = row.column(1).get(Integer.class); - String name = row.column(2).get(String.class); - LOGGER.log(Level.INFO, () -> String.format("Pokemon id=%d, name=%s", id, name)); - assertThat(valid.containsKey(id), equalTo(true)); - assertThat(name, equalTo(valid.get(id).getName())); - } - } - - /** - * Verify that the given row contains single data matching specified IDs range. - * - * @param maybeRow database query result to verify - * @param idMin beginning of ID range - * @param idMax end of ID range - */ - public static void verifyPokemonsIdRange(Optional maybeRow, int idMin, int idMax) { - Map valid = range(idMin, idMax); - assertThat(maybeRow.isPresent(), equalTo(true)); - DbRow row = maybeRow.get(); - Integer id = row.column(1).get(Integer.class); - String name = row.column(2).get(String.class); - assertThat(valid.containsKey(id), equalTo(true)); - assertThat(name, equalTo(valid.get(id).getName())); - } - - /** - * Verify that the given rows contain single record with expected data. - * - * @param rows database query result to verify - * @param expected data to compare with - */ - public static void verifyPokemon(List rows, Pokemon expected) { - assertThat(rows, notNullValue()); - assertThat(rows, hasSize(1)); - DbRow row = rows.get(0); - Integer id = row.column(1).get(Integer.class); - String name = row.column(2).get(String.class); - assertThat(id, equalTo(expected.getId())); - assertThat(name, expected.getName().equals(name)); - } - - /** - * Verify that the given rows contain single record with expected data. - * - * @param rows database query result to verify - * @param pokemon data to compare with - */ - public static void verifyPokemon(Stream rows, Pokemon pokemon) { - assertThat(rows, notNullValue()); - verifyPokemon(rows.toList(), pokemon); - } - - /** - * Verify that the given row contains single record with expected data. - * - * @param maybeRow database query result to verify - * @param expected data to compare with - */ - public static void verifyPokemon(Optional maybeRow, Pokemon expected) { - assertThat(maybeRow.isPresent(), equalTo(true)); - DbRow row = maybeRow.get(); - Integer id = row.column(1).get(Integer.class); - String name = row.column(2).get(String.class); - assertThat(id, equalTo(expected.getId())); - assertThat(name, expected.getName().equals(name)); - } - - /** - * Verify that the given data contains single record with expected data. - * - * @param actual database query result - * @param expected data to compare with - */ - public static void verifyPokemon(Pokemon actual, Pokemon expected) { - assertThat(actual.getId(), equalTo(expected.getId())); - assertThat(actual.getName(), equalTo(expected.getName())); - } - - /** - * Verify that provided data was successfully inserted into the database. - * - * @param dbClient database client - * @param result DML statement result - * @param data data to compare with - */ - public static void verifyInsertPokemon(DbClient dbClient, long result, Pokemon data) { - assertThat(result, equalTo(1L)); - Optional maybeRow = dbClient.execute() - .namedGet("select-pokemon-by-id", data.getId()); - - assertThat(maybeRow.isPresent(), equalTo(true)); - DbRow row = maybeRow.get(); - Integer id = row.column("id").get(Integer.class); - String name = row.column("name").get(String.class); - assertThat(id, equalTo(data.getId())); - assertThat(name, data.getName().equals(name)); - } - - /** - * Verify that provided data was successfully updated in the database. - * - * @param dbClient database client - * @param result DML statement result - * @param data data to compare with - */ - public static void verifyUpdatePokemon(DbClient dbClient, long result, Pokemon data) { - assertThat(result, equalTo(1L)); - Optional maybeRow = dbClient.execute() - .namedGet("select-pokemon-by-id", data.getId()); - verifyPokemon(maybeRow, data); - } - - /** - * Verify that provided data was successfully deleted from the database. - * - * @param dbClient database client - * @param result DML statement result - * @param expected data to compare with - */ - public static void verifyDeletePokemon(DbClient dbClient, long result, Pokemon expected) { - assertThat(result, equalTo(1L)); - Optional maybeRow = dbClient.execute() - .namedGet("select-pokemon-by-id", expected.getId()); - assertThat(maybeRow.isPresent(), equalTo(false)); - } - - private static Map range(int idMin, int idMax) { - Map map = new HashMap<>(POKEMONS.size()); - for (Map.Entry entry : POKEMONS.entrySet()) { - int id = entry.getKey(); - Pokemon pokemon = entry.getValue(); - if (id > idMin && id < idMax) { - map.put(id, pokemon); - } - } - return map; - } -} diff --git a/tests/integration/dbclient/common/src/main/java/module-info.java b/tests/integration/dbclient/common/src/main/java/module-info.java deleted file mode 100644 index 23fca963da9..00000000000 --- a/tests/integration/dbclient/common/src/main/java/module-info.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2023 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. - */ - -/** - * Helidon Database Client Integration Tests. - */ -module io.helidon.tests.integration.dbclient.common { - - requires org.junit.jupiter.api; - requires java.net.http; - requires jakarta.json; - requires hamcrest.all; - - requires io.helidon.common; - requires io.helidon.config; - requires io.helidon.dbclient; - requires io.helidon.dbclient.metrics; - requires io.helidon.webserver; - requires io.helidon.webserver.observe; - requires io.helidon.dbclient.health; - requires io.helidon.health; - requires io.helidon.webserver.observe.health; - - exports io.helidon.tests.integration.dbclient.common.spi; - exports io.helidon.tests.integration.dbclient.common.tests; - exports io.helidon.tests.integration.dbclient.common.utils; - exports io.helidon.tests.integration.dbclient.common.model; - - uses io.helidon.tests.integration.dbclient.common.spi.SetupProvider; - - provides io.helidon.dbclient.spi.DbMapperProvider - with io.helidon.tests.integration.dbclient.common.utils.MapperProvider; -} \ No newline at end of file diff --git a/tests/integration/harness/src/main/resources/META-INF/services/org.junit.jupiter.api.extension.Extension b/tests/integration/dbclient/common/src/main/resources/META-INF/services/io.helidon.common.mapper.spi.MapperProvider similarity index 77% rename from tests/integration/harness/src/main/resources/META-INF/services/org.junit.jupiter.api.extension.Extension rename to tests/integration/dbclient/common/src/main/resources/META-INF/services/io.helidon.common.mapper.spi.MapperProvider index 7ab5e9f9c7a..c8d66006551 100644 --- a/tests/integration/harness/src/main/resources/META-INF/services/org.junit.jupiter.api.extension.Extension +++ b/tests/integration/dbclient/common/src/main/resources/META-INF/services/io.helidon.common.mapper.spi.MapperProvider @@ -1,5 +1,5 @@ # -# Copyright (c) 2023 Oracle and/or its affiliates. +# Copyright (c) 2024 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. @@ -14,5 +14,4 @@ # limitations under the License. # -io.helidon.tests.integration.harness.SuiteLifeCycle -io.helidon.tests.integration.harness.SuiteParameterResolver +io.helidon.tests.integration.dbclient.common.MapperProviderImpl \ No newline at end of file diff --git a/tests/integration/dbclient/app/src/main/resources/META-INF/services/io.helidon.dbclient.spi.DbMapperProvider b/tests/integration/dbclient/common/src/main/resources/META-INF/services/io.helidon.dbclient.spi.DbMapperProvider similarity index 80% rename from tests/integration/dbclient/app/src/main/resources/META-INF/services/io.helidon.dbclient.spi.DbMapperProvider rename to tests/integration/dbclient/common/src/main/resources/META-INF/services/io.helidon.dbclient.spi.DbMapperProvider index a08ca6a9e1c..52cbfa84e0d 100644 --- a/tests/integration/dbclient/app/src/main/resources/META-INF/services/io.helidon.dbclient.spi.DbMapperProvider +++ b/tests/integration/dbclient/common/src/main/resources/META-INF/services/io.helidon.dbclient.spi.DbMapperProvider @@ -1,5 +1,5 @@ # -# Copyright (c) 2019, 2022 Oracle and/or its affiliates. +# Copyright (c) 2024 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. @@ -14,4 +14,4 @@ # limitations under the License. # -io.helidon.tests.integration.dbclient.app.dbmapper.DbClientMapperProvider +io.helidon.tests.integration.dbclient.common.DbMapperProviderImpl diff --git a/tests/integration/dbclient/common/src/main/resources/db-common.yaml b/tests/integration/dbclient/common/src/main/resources/db-common.yaml new file mode 100644 index 00000000000..fffece98bde --- /dev/null +++ b/tests/integration/dbclient/common/src/main/resources/db-common.yaml @@ -0,0 +1,68 @@ +# +# Copyright (c) 2024 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. +# +db: + create-schema: true + insert-dataset: true + missing-map-parameters-as-null: true + statements: + ping: "SELECT 0" + create-types: | + CREATE TABLE Types ( + id INTEGER NOT NULL PRIMARY KEY, + name VARCHAR(64) NOT NULL + ) + create-pokemons: | + CREATE TABLE Pokemons ( + id INTEGER NOT NULL PRIMARY KEY, + name VARCHAR(64) NOT NULL + ) + create-poketypes: | + CREATE TABLE PokemonTypes ( + id_pokemon INTEGER NOT NULL REFERENCES Pokemons(id) ON DELETE CASCADE, + id_type INTEGER NOT NULL REFERENCES Types(id) ON DELETE CASCADE + ) + drop-types: "DROP TABLE Types" + drop-pokemons: "DROP TABLE Pokemons" + drop-poketypes: "DROP TABLE PokemonTypes" + insert-type: "INSERT INTO Types(id, name) VALUES(?, ?)" + insert-pokemon: "INSERT INTO Pokemons(id, name) VALUES(?, ?)" + insert-poketype: "INSERT INTO PokemonTypes(id_pokemon, id_type) VALUES(?, ?)" + insert-pokemon-named-arg: "INSERT INTO Pokemons(id, name) VALUES(:id, :name)" + insert-pokemon-order-arg: "INSERT INTO Pokemons(id, name) VALUES(?, ?)" + insert-pokemon-order-arg-rev: "INSERT INTO Pokemons(name, id) VALUES(?, ?)" + update-pokemon-named-arg: "UPDATE Pokemons SET name=:name WHERE id=:id" + update-pokemon-order-arg: "UPDATE Pokemons SET name=? WHERE id=?" + delete-pokemon-named-arg: "DELETE FROM Pokemons WHERE id=:id" + delete-pokemon-order-arg: "DELETE FROM Pokemons WHERE id=?" + delete-pokemon-full-named-arg: "DELETE FROM Pokemons WHERE name=:name AND id=:id" + delete-pokemon-full-order-arg: "DELETE FROM Pokemons WHERE name=? AND id=?" + select-types: SELECT id as "id", name as "name" FROM Types + select-pokemons: SELECT id as "id", name as "name" FROM Pokemons + select-poketypes: SELECT id_pokemon as "id_pokemon", id_type as "id_type" FROM PokemonTypes p WHERE id_pokemon = ? + select-poketypes-all: SELECT id_pokemon as "id_pokemon", id_type as "id_type" FROM PokemonTypes + select-pokemon-named-arg: SELECT id as "id", name as "name" FROM Pokemons WHERE name=:name + select-pokemon-order-arg: SELECT id as "id", name as "name" FROM Pokemons WHERE name=? + select-pokemon-by-id: SELECT id as "id", name as "name" FROM Pokemons WHERE id=? + select-pokemons-idrng-named-arg: SELECT id as "id", name as "name" FROM Pokemons WHERE id > :idmin AND id < :idmax + select-pokemons-idrng-order-arg: SELECT id as "id", name as "name" FROM Pokemons WHERE id > ? AND id < ? + select-pokemons-idname-named-arg: SELECT id, name FROM Pokemons WHERE name=:name AND id=:id + select-pokemons-error-arg: SELECT id as "id", name as "name" FROM Pokemons WHERE id > :id AND name = ? + services: + metrics: + - type: TIMER + statement-types: [ "INSERT" ] + - type: COUNTER + statement-names: [ "select-pokemons", "insert-pokemon" ] diff --git a/tests/integration/dbclient/h2/README.md b/tests/integration/dbclient/h2/README.md new file mode 100644 index 00000000000..9b0ca0fe7b6 --- /dev/null +++ b/tests/integration/dbclient/h2/README.md @@ -0,0 +1,6 @@ +# DbClient Integration Test H2 + +To run this test: +```shell +mvn clean verify +``` diff --git a/tests/integration/dbclient/h2/pom.xml b/tests/integration/dbclient/h2/pom.xml index bae0df64c17..c5880b5c983 100644 --- a/tests/integration/dbclient/h2/pom.xml +++ b/tests/integration/dbclient/h2/pom.xml @@ -1,6 +1,6 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 io.helidon.tests.integration.dbclient - helidon-tests-integration-dbclient-project + helidon-tests-integration-dbclient-parent 4.1.0-SNAPSHOT - ../pom.xml + ../parent/pom.xml helidon-tests-integration-dbclient-h2 - Helidon Tests Integration Database Client H2 - - - true - + Helidon Tests Integration DbClient H2 - - io.helidon.tests.integration.dbclient - helidon-tests-integration-dbclient-common - ${project.version} - - - io.helidon.integrations.db - h2 - - - com.h2database - h2 - - - io.helidon.config - helidon-config - - - io.helidon.config - helidon-config-yaml - - - io.helidon.dbclient - helidon-dbclient - - - io.helidon.common - helidon-common-mapper - io.helidon.dbclient helidon-dbclient-jdbc - test io.helidon.dbclient - helidon-dbclient-hikari - test - - - org.slf4j - slf4j-jdk14 - test - - - org.junit.jupiter - junit-jupiter-api - test + helidon-dbclient-metrics-hikari - io.helidon.tests.integration - helidon-tests-integration-harness - ${project.version} - test + io.helidon.integrations.db + h2 - org.hamcrest - hamcrest-all - test + com.h2database + h2 - - - src/test/resources - true - - org.apache.maven.plugins - maven-surefire-plugin - - - **/*IT - - + maven-dependency-plugin + + + copy-libs + + org.apache.maven.plugins maven-failsafe-plugin - - ${maven.test.redirectTestOutputToFile} - methods - 10 - - true - - - io.helidon.tests.integration.dbclient:helidon-tests-integration-dbclient-common - - - io.helidon.tests.integration.dbclient.common.tests.*IT - - - test - integration-test integration-test verify diff --git a/tests/integration/dbclient/h2/src/main/java/io/helidon/tests/integration/dbclient/jdbc/H2SetupProvider.java b/tests/integration/dbclient/h2/src/main/java/io/helidon/tests/integration/dbclient/jdbc/H2SetupProvider.java deleted file mode 100644 index ddb6508c451..00000000000 --- a/tests/integration/dbclient/h2/src/main/java/io/helidon/tests/integration/dbclient/jdbc/H2SetupProvider.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2023 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.tests.integration.dbclient.jdbc; - -import java.nio.file.Paths; -import java.sql.SQLException; -import java.util.Map; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbExecute; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.common.model.Type; -import io.helidon.tests.integration.dbclient.common.spi.SetupProvider; -import io.helidon.tests.integration.dbclient.common.tests.MapperIT; - -import org.h2.tools.Server; - -/** - * H2 database setup. - * Provides tests {@link Config} and {@link DbClient} instance for junit tests. - * Starts and initializes H2 database. - */ -public class H2SetupProvider implements SetupProvider { - - private static final System.Logger LOGGER = System.getLogger(MapperIT.class.getName()); - private static final Config CONFIG = initConfig(); - private static final int TIMEOUT = 60; - - // Start and initialize H2 database - static { - Config dbConfig = CONFIG.get("db"); - startH2(dbConfig); - DbClient dbClient = DbClient.builder(dbConfig).build(); - waitForStart(dbClient); - initSchema(dbClient); - initData(dbClient); - } - - private static Config initConfig() { - return Config.create(ConfigSources.classpath("h2.yaml")); - } - - private static void startH2(Config config) { - String password = config.get("password").asString().get(); - String port = config.get("port").asString().get(); - String database = config.get("database").asString().get(); - String baseDir = Paths.get("").toAbsolutePath().resolve("target").resolve(database).toString(); - try { - Server.main( - "-web", - "-webAllowOthers", - "-tcp", - "-tcpAllowOthers", - "-tcpAllowOthers", - "-tcpPassword", - password, - "-tcpPort", - port, - "-baseDir", - baseDir, - "-ifNotExists"); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - - private static void waitForStart(DbClient dbClient) { - long endTm = 1000 * TIMEOUT + System.currentTimeMillis(); - while (true) { - try { - dbClient.execute().namedGet("ping"); - break; - } catch (Throwable th) { - if (System.currentTimeMillis() > endTm) { - throw new IllegalStateException("Database startup failed!", th); - } - LOGGER.log(System.Logger.Level.DEBUG, () -> String.format("Exception: %s", th.getMessage()), th); - try { - Thread.sleep(1000); - } catch (InterruptedException ignored) { - } - } - } - } - - private static void initSchema(DbClient dbClient) { - DbExecute exec = dbClient.execute(); - exec.namedDml("create-types"); - exec.namedDml("create-pokemons"); - exec.namedDml("create-poketypes"); - } - - private static void initData(DbClient dbClient) { - DbExecute exec = dbClient.execute(); - long count = 0; - for (Map.Entry entry : Type.TYPES.entrySet()) { - count += exec.namedInsert("insert-type", entry.getKey(), entry.getValue().name()); - } - - for (Map.Entry entry : Pokemon.POKEMONS.entrySet()) { - count += exec.namedInsert("insert-pokemon", entry.getKey(), entry.getValue().getName()); - } - - for (Map.Entry entry : Pokemon.POKEMONS.entrySet()) { - Pokemon pokemon = entry.getValue(); - for (Type type : pokemon.getTypes()) { - count += exec.namedInsert("insert-poketype", pokemon.getId(), type.id()); - } - } - LOGGER.log(System.Logger.Level.INFO, String.format("executed %s statements", count)); - } - - public H2SetupProvider() { - } - - @Override - public Config config() { - return CONFIG; - } - - @Override - public DbClient dbClient() { - return DbClient.builder(CONFIG.get("db")).build(); - } - -} diff --git a/etc/pods/pgsql.yaml b/tests/integration/dbclient/h2/src/main/resources/db.yaml similarity index 60% rename from etc/pods/pgsql.yaml rename to tests/integration/dbclient/h2/src/main/resources/db.yaml index 0c90f063a30..2ca138590f6 100644 --- a/etc/pods/pgsql.yaml +++ b/tests/integration/dbclient/h2/src/main/resources/db.yaml @@ -1,5 +1,5 @@ # -# Copyright (c) 2018, 2020 Oracle and/or its affiliates. +# Copyright (c) 2024 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. @@ -14,20 +14,15 @@ # limitations under the License. # -apiVersion: v1 -kind: Pod -metadata: - name: pgsql -spec: - containers: - - name: pgsql - image: postgres - ports: - - containerPort: 5432 - env: - - name: POSTGRES_USER - value: "user" - - name: POSTGRES_PASSWORD - value: "password" - - name: POSTGRES_DB - value: "pokemon" +db: + source: jdbc + connection: + url: jdbc:h2:mem:test;DATABASE_TO_UPPER=FALSE;TRACE_LEVEL_FILE=4 + username: sa + password: + poolName: test + initializationFailTimeout: -1 + connectionTimeout: 2000 + health-check: + type: query + statement: "SELECT 0" diff --git a/tests/integration/dbclient/app/src/main/resources/common.yaml b/tests/integration/dbclient/h2/src/main/resources/logging.properties similarity index 83% rename from tests/integration/dbclient/app/src/main/resources/common.yaml rename to tests/integration/dbclient/h2/src/main/resources/logging.properties index a9d5230bb30..d590b197673 100644 --- a/tests/integration/dbclient/app/src/main/resources/common.yaml +++ b/tests/integration/dbclient/h2/src/main/resources/logging.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2023 Oracle and/or its affiliates. +# Copyright (c) 2024 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. @@ -14,6 +14,5 @@ # limitations under the License. # -server: - port: 0 - host: 0.0.0.0 +handlers=org.slf4j.bridge.SLF4JBridgeHandler +.level=INFO diff --git a/tests/integration/dbclient/h2/src/main/resources/simplelogger.properties b/tests/integration/dbclient/h2/src/main/resources/simplelogger.properties new file mode 100644 index 00000000000..fcc605df165 --- /dev/null +++ b/tests/integration/dbclient/h2/src/main/resources/simplelogger.properties @@ -0,0 +1,22 @@ +# +# Copyright (c) 2024 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. +# +org.slf4j.simpleLogger.defaultLogLevel=warn +org.slf4j.simpleLogger.showThreadName=false +org.slf4j.simpleLogger.log.org.testcontainers=info +org.slf4j.simpleLogger.log.org.testcontainers.utility=error +org.slf4j.simpleLogger.log.io.helidon=info +org.slf4j.simpleLogger.log.org.hibernate=info +org.slf4j.simpleLogger.log.com.zaxxer=info diff --git a/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2LocalTest.java b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2LocalTest.java new file mode 100644 index 00000000000..e94c24e87f2 --- /dev/null +++ b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2LocalTest.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.h2; + +import java.util.Map; +import java.util.function.BiFunction; + +import io.helidon.config.Config; +import io.helidon.dbclient.DbClient; +import io.helidon.tests.integration.dbclient.common.LocalTextContext; + +/** + * Base class for the local tests. + */ +abstract class H2LocalTest { + + static LocalTextContext context(BiFunction factory) { + return LocalTextContext.create(factory, Map.of(), true); + } + + static void shutdown(LocalTextContext ctx) { + try { + ctx.db().execute().dml("SHUTDOWN"); + } catch (Throwable ignored) { + } + } +} diff --git a/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2MiscLocalTestIT.java b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2MiscLocalTestIT.java new file mode 100644 index 00000000000..8ac7b7d9426 --- /dev/null +++ b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2MiscLocalTestIT.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.h2; + +import io.helidon.tests.integration.dbclient.common.LocalTextContext; +import io.helidon.tests.integration.dbclient.common.MiscTest; +import io.helidon.tests.integration.dbclient.common.MiscTestImpl; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Local misc test. + */ +final class H2MiscLocalTestIT extends H2LocalTest implements MiscTest { + + static LocalTextContext ctx; + + @BeforeAll + static void setUp() { + ctx = context(MiscTestImpl::new); + } + + @AfterAll + static void tearDown() { + shutdown(ctx); + } + + @Test + @Override + public void testFlowControl() { + ctx.delegate().testFlowControl(); + } + + @Test + @Override + public void testStatementInterceptor() { + ctx.delegate().testStatementInterceptor(); + } + + @Test + @Override + public void testInsertWithOrderMapping() { + ctx.delegate().testInsertWithOrderMapping(); + } + + @Test + @Override + public void testInsertWithNamedMapping() { + ctx.delegate().testInsertWithNamedMapping(); + } + + @Test + @Override + public void testUpdateWithOrderMapping() { + ctx.delegate().testUpdateWithOrderMapping(); + } + + @Test + @Override + public void testUpdateWithNamedMapping() { + ctx.delegate().testUpdateWithNamedMapping(); + } + + @Test + @Override + public void testDeleteWithOrderMapping() { + ctx.delegate().testDeleteWithOrderMapping(); + } + + @Test + @Override + public void testDeleteWithNamedMapping() { + ctx.delegate().testDeleteWithNamedMapping(); + } + + @Test + @Override + public void testQueryWithMapping() { + ctx.delegate().testQueryWithMapping(); + } + + @Test + @Override + public void testGetWithMapping() { + ctx.delegate().testGetWithMapping(); + } +} diff --git a/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2MiscRemoteTestIT.java b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2MiscRemoteTestIT.java new file mode 100644 index 00000000000..186eea903dd --- /dev/null +++ b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2MiscRemoteTestIT.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.h2; + +import io.helidon.tests.integration.dbclient.common.MiscTest; + +import org.junit.jupiter.api.Test; + +/** + * Remote misc test. + */ +final class H2MiscRemoteTestIT extends H2RemoteTest implements MiscTest { + + H2MiscRemoteTestIT() { + super("/test/misc"); + } + + @Test + @Override + public void testFlowControl() { + remoteTest(); + } + + @Test + @Override + public void testStatementInterceptor() { + remoteTest(); + } + + @Test + @Override + public void testInsertWithOrderMapping() { + remoteTest(); + } + + @Test + @Override + public void testInsertWithNamedMapping() { + remoteTest(); + } + + @Test + @Override + public void testUpdateWithOrderMapping() { + remoteTest(); + } + + @Test + @Override + public void testUpdateWithNamedMapping() { + remoteTest(); + } + + @Test + @Override + public void testDeleteWithOrderMapping() { + remoteTest(); + } + + @Test + @Override + public void testDeleteWithNamedMapping() { + remoteTest(); + } + + @Test + @Override + public void testQueryWithMapping() { + remoteTest(); + } + + @Test + @Override + public void testGetWithMapping() { + remoteTest(); + } +} diff --git a/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2ObservabilityLocalTestIT.java b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2ObservabilityLocalTestIT.java new file mode 100644 index 00000000000..dc1b5048e0e --- /dev/null +++ b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2ObservabilityLocalTestIT.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.h2; + +import io.helidon.tests.integration.dbclient.common.DbClientITMain; +import io.helidon.tests.integration.dbclient.common.LocalTextContext; +import io.helidon.tests.integration.dbclient.common.ObservabilityTest; +import io.helidon.tests.integration.dbclient.common.ObservabilityTestImpl; +import io.helidon.webclient.http1.Http1Client; +import io.helidon.webserver.WebServerConfig; +import io.helidon.webserver.testing.junit5.ServerTest; +import io.helidon.webserver.testing.junit5.SetUpServer; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Local observability test. + */ +@ServerTest +final class H2ObservabilityLocalTestIT extends H2LocalTest implements ObservabilityTest { + + private static LocalTextContext ctx; + private static Http1Client client; + + @BeforeAll + static void beforeAll(Http1Client aClient) { + client = aClient; + } + + @SetUpServer + static void setUp(WebServerConfig.Builder builder) { + ctx = context((db, c) -> new ObservabilityTestImpl(db, c, () -> client)); + DbClientITMain.setup(ctx.db(), ctx.config(), builder); + } + + @AfterAll + static void tearDown() { + shutdown(ctx); + } + + @Test + @Override + public void testHttpHealthNoDetails() { + ctx.delegate().testHttpHealthNoDetails(); + } + + @Test + @Override + public void testHttpHealthDetails() { + ctx.delegate().testHttpHealthDetails(); + } + + @Test + @Override + public void testHttpMetrics() { + ctx.delegate().testHttpMetrics(); + } + + @Test + @Override + public void testHealthCheck() { + ctx.delegate().testHealthCheck(); + } + + @Test + @Override + public void testHealthCheckWithName() { + ctx.delegate().testHealthCheckWithName(); + } + + @Override + @SuppressWarnings("ALL") + public void testHealthCheckWithCustomNamedDML() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testHealthCheckWithCustomDML() { + throw new UnsupportedOperationException(); + } + + @Test + @Override + public void testHealthCheckWithCustomNamedQuery() { + ctx.delegate().testHealthCheckWithCustomNamedQuery(); + } + + @Test + @Override + public void testHealthCheckWithCustomQuery() { + ctx.delegate().testHealthCheckWithCustomQuery(); + } +} diff --git a/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2ObservabilityRemoteTestIT.java b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2ObservabilityRemoteTestIT.java new file mode 100644 index 00000000000..2a33a6f8536 --- /dev/null +++ b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2ObservabilityRemoteTestIT.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.h2; + +import io.helidon.tests.integration.dbclient.common.ObservabilityTest; + +import org.junit.jupiter.api.Test; + +/** + * Remote observability test. + */ +final class H2ObservabilityRemoteTestIT extends H2RemoteTest implements ObservabilityTest { + + H2ObservabilityRemoteTestIT() { + super("/test/observability"); + } + + @Test + @Override + public void testHttpHealthNoDetails() { + remoteTest(); + } + + @Test + @Override + public void testHttpHealthDetails() { + remoteTest(); + } + + @Test + @Override + public void testHttpMetrics() { + remoteTest(); + } + + @Test + @Override + public void testHealthCheck() { + remoteTest(); + } + + @Test + @Override + public void testHealthCheckWithName() { + remoteTest(); + } + + @Override + @SuppressWarnings("ALL") + public void testHealthCheckWithCustomNamedDML() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testHealthCheckWithCustomDML() { + throw new UnsupportedOperationException(); + } + + @Test + @Override + public void testHealthCheckWithCustomNamedQuery() { + remoteTest(); + } + + @Test + @Override + public void testHealthCheckWithCustomQuery() { + remoteTest(); + } +} diff --git a/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2RemoteTest.java b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2RemoteTest.java new file mode 100644 index 00000000000..c1eefb87c44 --- /dev/null +++ b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2RemoteTest.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.h2; + +import java.nio.file.Path; +import java.util.Map; + +import io.helidon.tests.integration.dbclient.common.RemoteTest; +import io.helidon.tests.integration.harness.ProcessRunner; +import io.helidon.tests.integration.harness.ProcessRunner.ExecMode; +import io.helidon.tests.integration.harness.WaitStrategy; +import io.helidon.tests.integration.harness.TestProcess; +import io.helidon.tests.integration.harness.TestProcesses; + +/** + * Base class for the remote tests. + */ +@TestProcesses +abstract class H2RemoteTest extends RemoteTest { + + @TestProcess + static final ProcessRunner PROCESS_RUNNER = ProcessRunner.of(ExecMode.CLASS_PATH) + .finalName("helidon-tests-integration-dbclient-h2") + .properties(Map.of("java.util.logging.config.file", Path.of("target/classes/logging.properties").toAbsolutePath())) + .waitingFor(WaitStrategy.waitForPort()); + + /** + * Create a new instance. + * + * @param path base path + */ + @SuppressWarnings("resource") + H2RemoteTest(String path) { + super(path, PROCESS_RUNNER.process().port()); + } +} diff --git a/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2SimpleLocalTestIT.java b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2SimpleLocalTestIT.java new file mode 100644 index 00000000000..c11f2c8b9e5 --- /dev/null +++ b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2SimpleLocalTestIT.java @@ -0,0 +1,378 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.h2; + +import io.helidon.tests.integration.dbclient.common.LocalTextContext; +import io.helidon.tests.integration.dbclient.common.SimpleTest; +import io.helidon.tests.integration.dbclient.common.SimpleTestImpl; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Local simple test. + */ +final class H2SimpleLocalTestIT extends H2LocalTest implements SimpleTest { + + static LocalTextContext ctx; + + @BeforeAll + static void setUp() { + ctx = context(SimpleTestImpl::new); + } + + @AfterAll + static void tearDown() { + shutdown(ctx); + } + + @Test + @Override + public void testCreateNamedDeleteStrStrOrderArgs() { + ctx.delegate().testCreateNamedDeleteStrStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedDeleteStrNamedArgs() { + ctx.delegate().testCreateNamedDeleteStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDeleteStrOrderArgs() { + ctx.delegate().testCreateNamedDeleteStrOrderArgs(); + } + + @Test + @Override + public void testCreateDeleteNamedArgs() { + ctx.delegate().testCreateDeleteNamedArgs(); + } + + @Test + @Override + public void testCreateDeleteOrderArgs() { + ctx.delegate().testCreateDeleteOrderArgs(); + } + + @Test + @Override + public void testNamedDeleteOrderArgs() { + ctx.delegate().testNamedDeleteOrderArgs(); + } + + @Test + @Override + public void testDeleteOrderArgs() { + ctx.delegate().testDeleteOrderArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithInsertStrStrNamedArgs() { + ctx.delegate().testCreateNamedDmlWithInsertStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithInsertStrNamedArgs() { + ctx.delegate().testCreateNamedDmlWithInsertStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithInsertStrOrderArgs() { + ctx.delegate().testCreateNamedDmlWithInsertStrOrderArgs(); + } + + @Test + @Override + public void testCreateDmlWithInsertNamedArgs() { + ctx.delegate().testCreateDmlWithInsertNamedArgs(); + } + + @Test + @Override + public void testCreateDmlWithInsertOrderArgs() { + ctx.delegate().testCreateDmlWithInsertOrderArgs(); + } + + @Test + @Override + public void testNamedDmlWithInsertOrderArgs() { + ctx.delegate().testNamedDmlWithInsertOrderArgs(); + } + + @Test + @Override + public void testDmlWithInsertOrderArgs() { + ctx.delegate().testDmlWithInsertOrderArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithUpdateStrStrNamedArgs() { + ctx.delegate().testCreateNamedDmlWithUpdateStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithUpdateStrNamedArgs() { + ctx.delegate().testCreateNamedDmlWithUpdateStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithUpdateStrOrderArgs() { + ctx.delegate().testCreateNamedDmlWithUpdateStrOrderArgs(); + } + + @Test + @Override + public void testCreateDmlWithUpdateNamedArgs() { + ctx.delegate().testCreateDmlWithUpdateNamedArgs(); + } + + @Test + @Override + public void testCreateDmlWithUpdateOrderArgs() { + ctx.delegate().testCreateDmlWithUpdateOrderArgs(); + } + + @Test + @Override + public void testNamedDmlWithUpdateOrderArgs() { + ctx.delegate().testNamedDmlWithUpdateOrderArgs(); + } + + @Test + @Override + public void testDmlWithUpdateOrderArgs() { + ctx.delegate().testDmlWithUpdateOrderArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithDeleteStrStrOrderArgs() { + ctx.delegate().testCreateNamedDmlWithDeleteStrStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithDeleteStrNamedArgs() { + ctx.delegate().testCreateNamedDmlWithDeleteStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithDeleteStrOrderArgs() { + ctx.delegate().testCreateNamedDmlWithDeleteStrOrderArgs(); + } + + @Test + @Override + public void testCreateDmlWithDeleteNamedArgs() { + ctx.delegate().testCreateDmlWithDeleteNamedArgs(); + } + + @Test + @Override + public void testCreateDmlWithDeleteOrderArgs() { + ctx.delegate().testCreateDmlWithDeleteOrderArgs(); + } + + @Test + @Override + public void testNamedDmlWithDeleteOrderArgs() { + ctx.delegate().testNamedDmlWithDeleteOrderArgs(); + } + + @Test + @Override + public void testDmlWithDeleteOrderArgs() { + ctx.delegate().testDmlWithDeleteOrderArgs(); + } + + @Test + @Override + public void testCreateNamedGetStrStrNamedArgs() { + ctx.delegate().testCreateNamedGetStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedGetStrNamedArgs() { + ctx.delegate().testCreateNamedGetStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedGetStrOrderArgs() { + ctx.delegate().testCreateNamedGetStrOrderArgs(); + } + + @Test + @Override + public void testCreateGetNamedArgs() { + ctx.delegate().testCreateGetNamedArgs(); + } + + @Test + @Override + public void testCreateGetOrderArgs() { + ctx.delegate().testCreateGetOrderArgs(); + } + + @Test + @Override + public void testNamedGetStrOrderArgs() { + ctx.delegate().testNamedGetStrOrderArgs(); + } + + @Test + @Override + public void testGetStrOrderArgs() { + ctx.delegate().testGetStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedInsertStrStrNamedArgs() { + ctx.delegate().testCreateNamedInsertStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedInsertStrNamedArgs() { + ctx.delegate().testCreateNamedInsertStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedInsertStrOrderArgs() { + ctx.delegate().testCreateNamedInsertStrOrderArgs(); + } + + @Test + @Override + public void testCreateInsertNamedArgs() { + ctx.delegate().testCreateInsertNamedArgs(); + } + + @Test + @Override + public void testCreateInsertOrderArgs() { + ctx.delegate().testCreateInsertOrderArgs(); + } + + @Test + @Override + public void testNamedInsertOrderArgs() { + ctx.delegate().testNamedInsertOrderArgs(); + } + + @Test + @Override + public void testInsertOrderArgs() { + ctx.delegate().testInsertOrderArgs(); + } + + @Test + @Override + public void testCreateNamedQueryStrStrOrderArgs() { + ctx.delegate().testCreateNamedQueryStrStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedQueryStrNamedArgs() { + ctx.delegate().testCreateNamedQueryStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedQueryStrOrderArgs() { + ctx.delegate().testCreateNamedQueryStrOrderArgs(); + } + + @Test + @Override + public void testCreateQueryNamedArgs() { + ctx.delegate().testCreateQueryNamedArgs(); + } + + @Test + @Override + public void testCreateQueryOrderArgs() { + ctx.delegate().testCreateQueryOrderArgs(); + } + + @Test + @Override + public void testNamedQueryOrderArgs() { + ctx.delegate().testNamedQueryOrderArgs(); + } + + @Test + @Override + public void testQueryOrderArgs() { + ctx.delegate().testQueryOrderArgs(); + } + + @Test + @Override + public void testCreateNamedUpdateStrStrNamedArgs() { + ctx.delegate().testCreateNamedUpdateStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedUpdateStrNamedArgs() { + ctx.delegate().testCreateNamedUpdateStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedUpdateStrOrderArgs() { + ctx.delegate().testCreateNamedUpdateStrOrderArgs(); + } + + @Test + @Override + public void testCreateUpdateNamedArgs() { + ctx.delegate().testCreateUpdateNamedArgs(); + } + + @Test + @Override + public void testCreateUpdateOrderArgs() { + ctx.delegate().testCreateUpdateOrderArgs(); + } + + @Test + @Override + public void testNamedUpdateNamedArgs() { + ctx.delegate().testNamedUpdateNamedArgs(); + } + + @Test + @Override + public void testUpdateOrderArgs() { + ctx.delegate().testUpdateOrderArgs(); + } +} diff --git a/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2SimpleRemoteTestIT.java b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2SimpleRemoteTestIT.java new file mode 100644 index 00000000000..17073783943 --- /dev/null +++ b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2SimpleRemoteTestIT.java @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.h2; + +import io.helidon.tests.integration.dbclient.common.SimpleTest; + +import org.junit.jupiter.api.Test; + +/** + * Remote simple test. + */ +final class H2SimpleRemoteTestIT extends H2RemoteTest implements SimpleTest { + + H2SimpleRemoteTestIT() { + super("/test/simple"); + } + + @Test + @Override + public void testCreateNamedDeleteStrStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDeleteStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDeleteStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDeleteNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithInsertStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithInsertStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithInsertStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDmlWithInsertNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDmlWithInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedDmlWithInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testDmlWithInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithUpdateStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithUpdateStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithUpdateStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDmlWithUpdateNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDmlWithUpdateOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedDmlWithUpdateOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testDmlWithUpdateOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithDeleteStrStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithDeleteStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithDeleteStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDmlWithDeleteNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDmlWithDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedDmlWithDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testDmlWithDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedGetStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedGetStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedGetStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateGetNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateGetOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedGetStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testGetStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedInsertStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedInsertStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedInsertStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateInsertNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryStrStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateQueryNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateQueryOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedQueryOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testQueryOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedUpdateStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedUpdateStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedUpdateStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateUpdateNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateUpdateOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedUpdateNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testUpdateOrderArgs() { + remoteTest(); + } +} diff --git a/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2StatementLocalTestIT.java b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2StatementLocalTestIT.java new file mode 100644 index 00000000000..e99d7e380b5 --- /dev/null +++ b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2StatementLocalTestIT.java @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.h2; + +import io.helidon.tests.integration.dbclient.common.LocalTextContext; +import io.helidon.tests.integration.dbclient.common.StatementTest; +import io.helidon.tests.integration.dbclient.common.StatementTestImpl; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Local statement test. + */ +final class H2StatementLocalTestIT extends H2LocalTest implements StatementTest { + + static LocalTextContext ctx; + + @BeforeAll + static void setUp() { + ctx = context(StatementTestImpl::new); + } + + @AfterAll + static void tearDown() { + shutdown(ctx); + } + + @Test + @Override + public void testCreateNamedQueryNonExistentStmt() { + ctx.delegate().testCreateNamedQueryNonExistentStmt(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithoutArgs() { + ctx.delegate().testCreateNamedQueryNamedAndOrderArgsWithoutArgs(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithArgs() { + ctx.delegate().testCreateNamedQueryNamedAndOrderArgsWithArgs(); + } + + @Test + @Override + public void testCreateNamedQueryNamedArgsSetOrderArg() { + ctx.delegate().testCreateNamedQueryNamedArgsSetOrderArg(); + } + + @Test + @Override + public void testCreateNamedQueryOrderArgsSetNamedArg() { + ctx.delegate().testCreateNamedQueryOrderArgsSetNamedArg(); + } + + @Test + @Override + public void testGetArrayParams() { + ctx.delegate().testGetArrayParams(); + } + + @Test + @Override + public void testGetListParams() { + ctx.delegate().testGetListParams(); + } + + @Test + @Override + public void testGetMapParams() { + ctx.delegate().testGetMapParams(); + } + + @Test + @Override + public void testGetOrderParam() { + ctx.delegate().testGetOrderParam(); + } + + @Test + @Override + public void testGetNamedParam() { + ctx.delegate().testGetNamedParam(); + } + + @Test + @Override + public void testGetMappedNamedParam() { + ctx.delegate().testGetMappedNamedParam(); + } + + @Test + @Override + public void testGetMappedOrderParam() { + ctx.delegate().testGetMappedOrderParam(); + } + + @Test + @Override + public void testQueryArrayParams() { + ctx.delegate().testQueryArrayParams(); + } + + @Test + @Override + public void testQueryListParams() { + ctx.delegate().testQueryListParams(); + } + + @Test + @Override + public void testQueryMapParams() { + ctx.delegate().testQueryMapParams(); + } + + @Test + @Override + public void testQueryMapMissingParams() { + ctx.delegate().testQueryMapMissingParams(); + } + + @Test + @Override + public void testQueryOrderParam() { + ctx.delegate().testQueryOrderParam(); + } + + @Test + @Override + public void testQueryNamedParam() { + ctx.delegate().testQueryNamedParam(); + } + + @Test + @Override + public void testQueryMappedNamedParam() { + ctx.delegate().testQueryMappedNamedParam(); + } + + @Test + @Override + public void testQueryMappedOrderParam() { + ctx.delegate().testQueryMappedOrderParam(); + } + + @Test + @Override + public void testDmlArrayParams() { + ctx.delegate().testDmlArrayParams(); + } + + @Test + @Override + public void testDmlListParams() { + ctx.delegate().testDmlListParams(); + } + + @Test + @Override + public void testDmlMapParams() { + ctx.delegate().testDmlMapParams(); + } + + @Test + @Override + public void testDmlOrderParam() { + ctx.delegate().testDmlOrderParam(); + } + + @Test + @Override + public void testDmlNamedParam() { + ctx.delegate().testDmlNamedParam(); + } + + @Test + @Override + public void testDmlMappedNamedParam() { + ctx.delegate().testDmlMappedNamedParam(); + } + + @Test + @Override + public void testDmlMappedOrderParam() { + ctx.delegate().testDmlMappedOrderParam(); + } +} diff --git a/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2StatementRemoteTestIT.java b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2StatementRemoteTestIT.java new file mode 100644 index 00000000000..f18997d2650 --- /dev/null +++ b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2StatementRemoteTestIT.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.h2; + +import io.helidon.tests.integration.dbclient.common.StatementTest; + +import org.junit.jupiter.api.Test; + +/** + * Remote statement test. + */ +final class H2StatementRemoteTestIT extends H2RemoteTest implements StatementTest { + + H2StatementRemoteTestIT() { + super("/test/statement"); + } + + @Test + @Override + public void testCreateNamedQueryNonExistentStmt() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithoutArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNamedArgsSetOrderArg() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryOrderArgsSetNamedArg() { + remoteTest(); + } + + @Test + @Override + public void testGetArrayParams() { + remoteTest(); + } + + @Test + @Override + public void testGetListParams() { + remoteTest(); + } + + @Test + @Override + public void testGetMapParams() { + remoteTest(); + } + + @Test + @Override + public void testGetOrderParam() { + remoteTest(); + } + + @Test + @Override + public void testGetNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testGetMappedNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testGetMappedOrderParam() { + remoteTest(); + } + + @Test + @Override + public void testQueryArrayParams() { + remoteTest(); + } + + @Test + @Override + public void testQueryListParams() { + remoteTest(); + } + + @Test + @Override + public void testQueryMapParams() { + remoteTest(); + } + + @Override + public void testQueryMapMissingParams() { + remoteTest(); + } + + @Test + @Override + public void testQueryOrderParam() { + remoteTest(); + } + + @Test + @Override + public void testQueryNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testQueryMappedNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testQueryMappedOrderParam() { + remoteTest(); + } + + @Test + @Override + public void testDmlArrayParams() { + remoteTest(); + } + + @Test + @Override + public void testDmlListParams() { + remoteTest(); + } + + @Test + @Override + public void testDmlMapParams() { + remoteTest(); + } + + @Test + @Override + public void testDmlOrderParam() { + remoteTest(); + } + + @Test + @Override + public void testDmlNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testDmlMappedNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testDmlMappedOrderParam() { + remoteTest(); + } +} diff --git a/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2TransactionLocalTestIT.java b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2TransactionLocalTestIT.java new file mode 100644 index 00000000000..92e36d1cafe --- /dev/null +++ b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2TransactionLocalTestIT.java @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.h2; + +import io.helidon.tests.integration.dbclient.common.LocalTextContext; +import io.helidon.tests.integration.dbclient.common.TransactionTest; +import io.helidon.tests.integration.dbclient.common.TransactionTestImpl; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Local transaction test. + */ +final class H2TransactionLocalTestIT extends H2LocalTest implements TransactionTest { + + static LocalTextContext ctx; + + @BeforeAll + static void setUp() { + ctx = context(TransactionTestImpl::new); + } + + @AfterAll + static void tearDown() { + shutdown(ctx); + } + + @Test + @Override + public void testCreateNamedDeleteStrStrOrderArgs() { + ctx.delegate().testCreateNamedDeleteStrStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedDeleteStrNamedArgs() { + ctx.delegate().testCreateNamedDeleteStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDeleteStrOrderArgs() { + ctx.delegate().testCreateNamedDeleteStrOrderArgs(); + } + + @Test + @Override + public void testCreateDeleteNamedArgs() { + ctx.delegate().testCreateDeleteNamedArgs(); + } + + @Test + @Override + public void testCreateDeleteOrderArgs() { + ctx.delegate().testCreateDeleteOrderArgs(); + } + + @Test + @Override + public void testNamedDeleteOrderArgs() { + ctx.delegate().testNamedDeleteOrderArgs(); + } + + @Test + @Override + public void testDeleteOrderArgs() { + ctx.delegate().testDeleteOrderArgs(); + } + + @Test + @Override + public void testCreateNamedQueryNonExistentStmt() { + ctx.delegate().testCreateNamedQueryNonExistentStmt(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithoutArgs() { + ctx.delegate().testCreateNamedQueryNamedAndOrderArgsWithoutArgs(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithArgs() { + ctx.delegate().testCreateNamedQueryNamedAndOrderArgsWithArgs(); + } + + @Test + @Override + public void testCreateNamedQueryNamedArgsSetOrderArg() { + ctx.delegate().testCreateNamedQueryNamedArgsSetOrderArg(); + } + + @Test + @Override + public void testCreateNamedQueryOrderArgsSetNamedArg() { + ctx.delegate().testCreateNamedQueryOrderArgsSetNamedArg(); + } + + @Test + @Override + public void testCreateNamedGetStrStrNamedArgs() { + ctx.delegate().testCreateNamedGetStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedGetStrNamedArgs() { + ctx.delegate().testCreateNamedGetStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedGetStrOrderArgs() { + ctx.delegate().testCreateNamedGetStrOrderArgs(); + } + + @Test + @Override + public void testCreateGetNamedArgs() { + ctx.delegate().testCreateGetNamedArgs(); + } + + @Test + @Override + public void testCreateGetOrderArgs() { + ctx.delegate().testCreateGetOrderArgs(); + } + + @Test + @Override + public void testNamedGetStrOrderArgs() { + ctx.delegate().testNamedGetStrOrderArgs(); + } + + @Test + @Override + public void testGetStrOrderArgs() { + ctx.delegate().testGetStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedInsertStrStrNamedArgs() { + ctx.delegate().testCreateNamedInsertStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedInsertStrNamedArgs() { + ctx.delegate().testCreateNamedInsertStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedInsertStrOrderArgs() { + ctx.delegate().testCreateNamedInsertStrOrderArgs(); + } + + @Test + @Override + public void testCreateInsertNamedArgs() { + ctx.delegate().testCreateInsertNamedArgs(); + } + + @Test + @Override + public void testCreateInsertOrderArgs() { + ctx.delegate().testCreateInsertOrderArgs(); + } + + @Test + @Override + public void testNamedInsertOrderArgs() { + ctx.delegate().testNamedInsertOrderArgs(); + } + + @Test + @Override + public void testInsertOrderArgs() { + ctx.delegate().testInsertOrderArgs(); + } + + @Test + @Override + public void testCreateNamedQueryStrStrOrderArgs() { + ctx.delegate().testCreateNamedQueryStrStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedQueryStrNamedArgs() { + ctx.delegate().testCreateNamedQueryStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedQueryStrOrderArgs() { + ctx.delegate().testCreateNamedQueryStrOrderArgs(); + } + + @Test + @Override + public void testCreateQueryNamedArgs() { + ctx.delegate().testCreateQueryNamedArgs(); + } + + @Test + @Override + public void testCreateQueryOrderArgs() { + ctx.delegate().testCreateQueryOrderArgs(); + } + + @Test + @Override + public void testNamedQueryOrderArgs() { + ctx.delegate().testNamedQueryOrderArgs(); + } + + @Test + @Override + public void testQueryOrderArgs() { + ctx.delegate().testQueryOrderArgs(); + } + + @Test + @Override + public void testCreateNamedUpdateStrStrNamedArgs() { + ctx.delegate().testCreateNamedUpdateStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedUpdateStrNamedArgs() { + ctx.delegate().testCreateNamedUpdateStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedUpdateStrOrderArgs() { + ctx.delegate().testCreateNamedUpdateStrOrderArgs(); + } + + @Test + @Override + public void testCreateUpdateNamedArgs() { + ctx.delegate().testCreateUpdateNamedArgs(); + } + + @Test + @Override + public void testCreateUpdateOrderArgs() { + ctx.delegate().testCreateUpdateOrderArgs(); + } + + @Test + @Override + public void testNamedUpdateNamedArgs() { + ctx.delegate().testNamedUpdateNamedArgs(); + } + + @Test + @Override + public void testUpdateOrderArgs() { + ctx.delegate().testUpdateOrderArgs(); + } +} diff --git a/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2TransactionRemoteTestIT.java b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2TransactionRemoteTestIT.java new file mode 100644 index 00000000000..be12d2c9692 --- /dev/null +++ b/tests/integration/dbclient/h2/src/test/java/io/helidon/tests/integration/dbclient/h2/H2TransactionRemoteTestIT.java @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.h2; + +import io.helidon.tests.integration.dbclient.common.TransactionTest; + +import org.junit.jupiter.api.Test; + +/** + * Remote transaction test. + */ +final class H2TransactionRemoteTestIT extends H2RemoteTest implements TransactionTest { + + H2TransactionRemoteTestIT() { + super("/test/transaction"); + } + + @Test + @Override + public void testCreateNamedDeleteStrStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDeleteStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDeleteStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDeleteNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNonExistentStmt() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithoutArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNamedArgsSetOrderArg() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryOrderArgsSetNamedArg() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedGetStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedGetStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedGetStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateGetNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateGetOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedGetStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testGetStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedInsertStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedInsertStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedInsertStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateInsertNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryStrStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateQueryNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateQueryOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedQueryOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testQueryOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedUpdateStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedUpdateStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedUpdateStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateUpdateNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateUpdateOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedUpdateNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testUpdateOrderArgs() { + remoteTest(); + } +} diff --git a/tests/integration/dbclient/h2/src/test/resources/h2.yaml b/tests/integration/dbclient/h2/src/test/resources/h2.yaml deleted file mode 100644 index 8e8ab7dc122..00000000000 --- a/tests/integration/dbclient/h2/src/test/resources/h2.yaml +++ /dev/null @@ -1,63 +0,0 @@ -# -# Copyright (c) 2019, 2024 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. -# -db: - source: jdbc - host: "localhost" - port: 9092 - password: "password" - database: "test" - missing-map-parameters-as-null: true - connection: - url: jdbc:h2:tcp://${db.host}:${db.port}/${db.database};DATABASE_TO_UPPER=FALSE - health-check: - type: query - statement: "SELECT 0" - statements: - ping: "SELECT 0" - ping-query: "SELECT 0" - create-types: "CREATE TABLE Types (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(64) NOT NULL)" - create-pokemons: "CREATE TABLE Pokemons (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(64) NOT NULL)" - create-poketypes: "CREATE TABLE PokemonTypes (id_pokemon INTEGER NOT NULL REFERENCES Pokemons(id), id_type INTEGER NOT NULL REFERENCES Types(id))" - drop-types: "DROP TABLE Types" - drop-pokemons: "DROP TABLE Pokemons" - drop-poketypes: "DROP TABLE PokemonTypes" - insert-type: "INSERT INTO Types(id, name) VALUES(?, ?)" - insert-pokemon: "INSERT INTO Pokemons(id, name) VALUES(?, ?)" - insert-poketype: "INSERT INTO PokemonTypes(id_pokemon, id_type) VALUES(?, ?)" - select-types: "SELECT id, name FROM Types" - select-pokemons: "SELECT id, name FROM Pokemons" - select-poketypes: "SELECT id_pokemon, id_type FROM PokemonTypes p WHERE id_pokemon = ?" - select-poketypes-all: "SELECT id_pokemon, id_type FROM PokemonTypes" - select-max-id: "SELECT MAX(id) FROM Pokemons" - select-pokemon-named-arg: "SELECT id, name FROM Pokemons WHERE name=:name" - select-pokemon-order-arg: "SELECT id, name FROM Pokemons WHERE name=?" - insert-pokemon-named-arg: "INSERT INTO Pokemons(id, name) VALUES(:id, :name)" - insert-pokemon-order-arg: "INSERT INTO Pokemons(id, name) VALUES(?, ?)" - insert-pokemon-order-arg-rev: "INSERT INTO Pokemons(name, id) VALUES(?, ?)" - select-pokemon-by-id: "SELECT id, name FROM Pokemons WHERE id=?" - update-pokemon-named-arg: "UPDATE Pokemons SET name=:name WHERE id=:id" - update-pokemon-order-arg: "UPDATE Pokemons SET name=? WHERE id=?" - delete-pokemon-named-arg: "DELETE FROM Pokemons WHERE id=:id" - delete-pokemon-order-arg: "DELETE FROM Pokemons WHERE id=?" - delete-pokemon-full-named-arg: "DELETE FROM Pokemons WHERE name=:name AND id=:id" - delete-pokemon-full-order-arg: "DELETE FROM Pokemons WHERE name=? AND id=?" - select-pokemons-idrng-named-arg: "SELECT id, name FROM Pokemons WHERE id > :idmin AND id < :idmax" - select-pokemons-idrng-order-arg: "SELECT id, name FROM Pokemons WHERE id > ? AND id < ?" - select-pokemons-error-arg: "SELECT id, name FROM Pokemons WHERE id > :id AND name = ?" - select-pokemons-idname-named-arg: "SELECT id, name FROM Pokemons WHERE name=:name AND id=:id" - -test: - ping-dml: false diff --git a/tests/integration/dbclient/mongodb/README.md b/tests/integration/dbclient/mongodb/README.md new file mode 100644 index 00000000000..cbc29d04ab9 --- /dev/null +++ b/tests/integration/dbclient/mongodb/README.md @@ -0,0 +1,22 @@ +# DbClient Integration Test MongoDB + +To run this test: +```shell +mvn clean verify +``` + +Build the Docker image: +```shell +docker build etc/docker -t mongodb +``` + +Start the database: +```shell +docker run -d \ + --name mongodb \ + -e MONGO_DB=pokemon \ + -e MONGO_USER=test \ + -e MONGO_PASSWORD=mongo123 \ + -p 27017:27017 \ + mongodb +``` diff --git a/tests/integration/dbclient/mongodb/etc/docker/Dockerfile b/tests/integration/dbclient/mongodb/etc/docker/Dockerfile new file mode 100644 index 00000000000..0068a00ad6d --- /dev/null +++ b/tests/integration/dbclient/mongodb/etc/docker/Dockerfile @@ -0,0 +1,26 @@ +# +# Copyright (c) 2024 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. +# + +FROM oraclelinux:9-slim + +ADD mongodb-org-7.0.repo /etc/yum.repos.d/ +RUN microdnf install mongodb-org -y && microdnf clean all +ADD entrypoint.sh /usr/local/bin/ + +ENTRYPOINT ["entrypoint.sh"] +STOPSIGNAL SIGINT +EXPOSE 27017 +CMD ["mongod"] diff --git a/tests/integration/dbclient/mongodb/etc/docker/entrypoint.sh b/tests/integration/dbclient/mongodb/etc/docker/entrypoint.sh new file mode 100755 index 00000000000..25f2c935fea --- /dev/null +++ b/tests/integration/dbclient/mongodb/etc/docker/entrypoint.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2024 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. +# +set -Eeom pipefail + +mkdir -p /data/db + +# redirect stdout and stderr and stderr to log file +: > /var/log/mongodb/mongod.log +exec 2> >(tee -a /var/log/mongodb/mongod.log >&2) > >(tee -a /var/log/mongodb/mongod.log) + +# Add argument +args=("${@}") +args+=("--bind_ip_all") + +# start in the background +exec "${args[@]}" & + +# wait for started +while true ; do + grep "mongod startup complete" /var/log/mongodb/mongod.log > /dev/null && break + sleep 2 +done + +echo "Initializing database..." +mongosh --host 127.0.0.1 --port 27017 --quiet admin <<-EOJS + use ${MONGO_DB:-test} + db.createUser({ + user: "${MONGO_USER:-test}", + pwd: "${MONGO_PASSWORD:-test123}", + roles: [{role: "readWrite", db: "${MONGO_DB:-test}"}] + }) +EOJS + +echo "Container ready!" +fg diff --git a/tests/integration/dbclient/mongodb/etc/docker/mongodb-org-7.0.repo b/tests/integration/dbclient/mongodb/etc/docker/mongodb-org-7.0.repo new file mode 100644 index 00000000000..388ee53c357 --- /dev/null +++ b/tests/integration/dbclient/mongodb/etc/docker/mongodb-org-7.0.repo @@ -0,0 +1,6 @@ +[mongodb-org-7.0] +name=MongoDB Repository +baseurl=https://repo.mongodb.org/yum/redhat/9/mongodb-org/7.0/x86_64/ +gpgcheck=1 +enabled=1 +gpgkey=https://pgp.mongodb.com/server-7.0.asc diff --git a/tests/integration/dbclient/mongodb/pom.xml b/tests/integration/dbclient/mongodb/pom.xml index 9ece9d7fe3b..676b1d57dc2 100644 --- a/tests/integration/dbclient/mongodb/pom.xml +++ b/tests/integration/dbclient/mongodb/pom.xml @@ -16,113 +16,48 @@ --> + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 io.helidon.tests.integration.dbclient - helidon-tests-integration-dbclient-project + helidon-tests-integration-dbclient-parent 4.1.0-SNAPSHOT - ../pom.xml + ../parent/pom.xml helidon-tests-integration-dbclient-mongodb - Helidon Tests Integration Database Client MongoDB - - - 27017 - 127.0.0.1 - test - helidon - h3l1d0n - root - I4mGr00t - true - + Helidon Tests Integration DbClient MongoDB - - io.helidon.tests.integration.dbclient - helidon-tests-integration-dbclient-common - ${project.version} - test - - - io.helidon.config - helidon-config - test - - - io.helidon.config - helidon-config-yaml - test - io.helidon.dbclient helidon-dbclient-mongodb - test - - - org.junit.jupiter - junit-jupiter-api - test - - - io.helidon.tests.integration - helidon-tests-integration-harness - ${project.version} - test - - - org.hamcrest - hamcrest-all - test - - - src/test/resources - true - - org.apache.maven.plugins - maven-surefire-plugin - - - **/*IT - - + maven-dependency-plugin + + + copy-libs + + org.apache.maven.plugins maven-failsafe-plugin - - ${maven.test.redirectTestOutputToFile} - methods - 10 - - true - - - test - integration-test integration-test verify - - - **/*SuiteIT - - - + \ No newline at end of file diff --git a/tests/integration/dbclient/mongodb/src/main/resources/db.yaml b/tests/integration/dbclient/mongodb/src/main/resources/db.yaml new file mode 100644 index 00000000000..003f8d9306b --- /dev/null +++ b/tests/integration/dbclient/mongodb/src/main/resources/db.yaml @@ -0,0 +1,202 @@ +# +# Copyright (c) 2024 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. +# + +db: + create-schema: false + source: mongoDb + connection: + url: mongodb://localhost:27017/pokemon + username: test + password: mongo123 + health-check: + type: query + statement: | + { + "operation": "command", + "query": { "ping": 1 } + } + statements: + ping: | + { + "operation": "command", + "query": { ping: 1 } + } + delete-types: | + { + "collection": "types", + "operation": "delete", + "query": { } + } + delete-pokemons: | + { + "collection": "pokemons", + "operation": "delete", + "query": { } + } + delete-poketypes: | + { + "collection": "pokemon_types", + "operation": "delete", + "query": { } + } + insert-type: | + { + "collection": "types", + "value": { + "id": ?, + "type": ? + } + } + insert-pokemon: | + { + "collection": "pokemons", + "value": { + "id": ?, + "name": ? + } + } + insert-poketype: | + { + "collection": "pokemon_types", + "value": { + "id_pokemon": ?, + "id_type": ? + } + } + select-types: | + { + "collection": "types", + "projection": { id: 1, type: 1, _id: 0 }, + "query": {} + } + select-pokemons: | + { + "collection": "pokemons", + "projection": { id: 1, name: 1, _id: 0 }, + "query": {} + } + select-poketypes: | + { + "collection": "pokemon_types", + "projection": { id_pokemon: 1, id_type: 1, _id: 0 }, + "query": { id_pokemon: ? } + } + select-poketypes-all: | + { + "collection": "pokemon_types", + "projection": { id_pokemon: 1, id_type: 1, _id: 0 }, + "query": {} + } + select-pokemon-named-arg: | + { + "collection": "pokemons", + "operation": "query", + "projection": { id: 1, name: 1, _id: 0 }, + "query": { name: $name } + } + select-pokemon-order-arg: | + { + "collection": "pokemons", + "operation": "query", + "projection": { id: 1, name: 1, _id: 0 }, + "query": { name: ? } + } + insert-pokemon-named-arg: | + { + "collection": "pokemons", + "operation": "insert", + "value": { + "id": $id, + "name": $name + } + } + insert-pokemon-order-arg: | + { + "collection": "pokemons", + "operation": "insert", + "value": { + "id": ?, + "name": ? + } + } + insert-pokemon-order-arg-rev: | + { + "collection": "pokemons", + "operation": "insert", + "value": { + "name": ?, + "id": ? + } + } + select-pokemon-by-id: | + { + "collection": "pokemons", + "operation": "query", + "projection": { id: 1, name: 1, _id: 0 }, + "query": { id: ? } + } + update-pokemon-named-arg: | + { + "collection": "pokemons", + "operation": "update", + "value":{ $set: { "name": $name } }, + "query": { id: $id } + } + update-pokemon-order-arg: | + { + "collection": "pokemons", + "operation": "update", + "value":{ $set: { "name": ? } }, + "query": { id: ? } + } + delete-pokemon-named-arg: | + { + "collection": "pokemons", + "operation": "delete", + "query": { id: $id } + } + delete-pokemon-order-arg: | + { + "collection": "pokemons", + "operation": "delete", + "query": { id: ? } + } + delete-pokemon-full-named-arg: | + { + "collection": "pokemons", + "operation": "delete", + "query": { $and: [ {name: $name }, { id: $id } ] } + } + delete-pokemon-full-order-arg: | + { + "collection": "pokemons", + "operation": "delete", + "query": { $and: [ {name: ? }, { id: ? } ] } + } + select-pokemons-idrng-named-arg: | + { + "collection": "pokemons", + "operation": "query", + "projection": { id: 1, name: 1, _id: 0 }, + "query": { $and: [ { id: { $gt: $idmin } }, { id: { $lt: $idmax } } ] } + } + select-pokemons-idrng-order-arg: | + { + "collection": "pokemons", + "operation": "query", + "projection": { id: 1, name: 1, _id: 0 }, + "query": { $and: [ { id: { $gt: ? } }, { id: { $lt: ? } } ] } + } diff --git a/tests/integration/harness/src/main/resources/META-INF/services/org.junit.platform.launcher.TestExecutionListener b/tests/integration/dbclient/mongodb/src/main/resources/logging.properties similarity index 83% rename from tests/integration/harness/src/main/resources/META-INF/services/org.junit.platform.launcher.TestExecutionListener rename to tests/integration/dbclient/mongodb/src/main/resources/logging.properties index a0b19044e6f..d590b197673 100644 --- a/tests/integration/harness/src/main/resources/META-INF/services/org.junit.platform.launcher.TestExecutionListener +++ b/tests/integration/dbclient/mongodb/src/main/resources/logging.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2023 Oracle and/or its affiliates. +# Copyright (c) 2024 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. @@ -13,4 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # -io.helidon.tests.integration.harness.SuiteFinder + +handlers=org.slf4j.bridge.SLF4JBridgeHandler +.level=INFO diff --git a/tests/integration/dbclient/mongodb/src/main/resources/simplelogger.properties b/tests/integration/dbclient/mongodb/src/main/resources/simplelogger.properties new file mode 100644 index 00000000000..fcc605df165 --- /dev/null +++ b/tests/integration/dbclient/mongodb/src/main/resources/simplelogger.properties @@ -0,0 +1,22 @@ +# +# Copyright (c) 2024 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. +# +org.slf4j.simpleLogger.defaultLogLevel=warn +org.slf4j.simpleLogger.showThreadName=false +org.slf4j.simpleLogger.log.org.testcontainers=info +org.slf4j.simpleLogger.log.org.testcontainers.utility=error +org.slf4j.simpleLogger.log.io.helidon=info +org.slf4j.simpleLogger.log.org.hibernate=info +org.slf4j.simpleLogger.log.com.zaxxer=info diff --git a/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBLocalTest.java b/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBLocalTest.java new file mode 100644 index 00000000000..4e15519ade5 --- /dev/null +++ b/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBLocalTest.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.mongodb; + +import java.util.function.BiFunction; + +import io.helidon.config.Config; +import io.helidon.dbclient.DbClient; +import io.helidon.tests.integration.dbclient.common.LocalTextContext; + +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +/** + * Base class for the local tests. + */ +@Testcontainers(disabledWithoutDocker = true) +abstract class MongoDBLocalTest { + + @Container + static final GenericContainer CONTAINER = MongoDBTestContainer.CONTAINER; + + static LocalTextContext context(BiFunction factory) { + return LocalTextContext.create(factory, MongoDBTestContainer.config(), false); + } +} diff --git a/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBMiscLocalTestIT.java b/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBMiscLocalTestIT.java new file mode 100644 index 00000000000..a24521e7eef --- /dev/null +++ b/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBMiscLocalTestIT.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.mongodb; + +import io.helidon.tests.integration.dbclient.common.LocalTextContext; +import io.helidon.tests.integration.dbclient.common.MiscTest; +import io.helidon.tests.integration.dbclient.common.MiscTestImpl; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Local misc test. + */ +final class MongoDBMiscLocalTestIT extends MongoDBLocalTest implements MiscTest { + + static LocalTextContext ctx; + + @BeforeAll + static void setUp() { + ctx = context(MiscTestImpl::new); + } + + @Test + @Override + public void testFlowControl() { + ctx.delegate().testFlowControl(); + } + + @Test + @Override + public void testStatementInterceptor() { + ctx.delegate().testStatementInterceptor(); + } + + @Test + @Override + public void testInsertWithOrderMapping() { + ctx.delegate().testInsertWithOrderMapping(); + } + + @Test + @Override + public void testInsertWithNamedMapping() { + ctx.delegate().testInsertWithNamedMapping(); + } + + @Test + @Override + public void testUpdateWithOrderMapping() { + ctx.delegate().testUpdateWithOrderMapping(); + } + + @Test + @Override + public void testUpdateWithNamedMapping() { + ctx.delegate().testUpdateWithNamedMapping(); + } + + @Test + @Override + public void testDeleteWithOrderMapping() { + ctx.delegate().testDeleteWithOrderMapping(); + } + + @Test + @Override + public void testDeleteWithNamedMapping() { + ctx.delegate().testDeleteWithNamedMapping(); + } + + @Test + @Override + public void testQueryWithMapping() { + ctx.delegate().testQueryWithMapping(); + } + + @Test + @Override + public void testGetWithMapping() { + ctx.delegate().testGetWithMapping(); + } +} diff --git a/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBMiscRemoteTestIT.java b/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBMiscRemoteTestIT.java new file mode 100644 index 00000000000..4381fe71cc3 --- /dev/null +++ b/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBMiscRemoteTestIT.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.mongodb; + +import io.helidon.tests.integration.dbclient.common.MiscTest; + +import org.junit.jupiter.api.Test; + +/** + * Remote misc test. + */ +final class MongoDBMiscRemoteTestIT extends MongoDBRemoteTest implements MiscTest { + + MongoDBMiscRemoteTestIT() { + super("/test/misc"); + } + + @Test + @Override + public void testFlowControl() { + remoteTest(); + } + + @Test + @Override + public void testStatementInterceptor() { + remoteTest(); + } + + @Test + @Override + public void testInsertWithOrderMapping() { + remoteTest(); + } + + @Test + @Override + public void testInsertWithNamedMapping() { + remoteTest(); + } + + @Test + @Override + public void testUpdateWithOrderMapping() { + remoteTest(); + } + + @Test + @Override + public void testUpdateWithNamedMapping() { + remoteTest(); + } + + @Test + @Override + public void testDeleteWithOrderMapping() { + remoteTest(); + } + + @Test + @Override + public void testDeleteWithNamedMapping() { + remoteTest(); + } + + @Test + @Override + public void testQueryWithMapping() { + remoteTest(); + } + + @Test + @Override + public void testGetWithMapping() { + remoteTest(); + } +} diff --git a/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBObservabilityLocalTestIT.java b/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBObservabilityLocalTestIT.java new file mode 100644 index 00000000000..1e4ab53cd9c --- /dev/null +++ b/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBObservabilityLocalTestIT.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.mongodb; + +import io.helidon.tests.integration.dbclient.common.DbClientITMain; +import io.helidon.tests.integration.dbclient.common.LocalTextContext; +import io.helidon.tests.integration.dbclient.common.ObservabilityTest; +import io.helidon.tests.integration.dbclient.common.ObservabilityTestImpl; +import io.helidon.webclient.http1.Http1Client; +import io.helidon.webserver.WebServerConfig; +import io.helidon.webserver.testing.junit5.ServerTest; +import io.helidon.webserver.testing.junit5.SetUpServer; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Local observability test. + */ +@ServerTest +final class MongoDBObservabilityLocalTestIT extends MongoDBLocalTest implements ObservabilityTest { + + private static Http1Client client; + private static LocalTextContext ctx; + + @BeforeAll + static void beforeAll(Http1Client aClient) { + client = aClient; + } + + @SetUpServer + static void setUp(WebServerConfig.Builder builder) { + ctx = context((db, c) -> new ObservabilityTestImpl(db, c, () -> client)); + DbClientITMain.setup(ctx.db(), ctx.config(), builder); + } + + @Test + @Override + public void testHttpHealthNoDetails() { + ctx.delegate().testHttpHealthNoDetails(); + } + + @Test + @Override + public void testHttpHealthDetails() { + ctx.delegate().testHttpHealthDetails(); + } + + @Test + @Override + public void testHttpMetrics() { + ctx.delegate().testHttpMetrics(); + } + + @Test + @Override + public void testHealthCheck() { + ctx.delegate().testHealthCheck(); + } + + @Test + @Override + public void testHealthCheckWithName() { + ctx.delegate().testHealthCheckWithName(); + } + + @Override + @SuppressWarnings("ALL") + public void testHealthCheckWithCustomNamedDML() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testHealthCheckWithCustomDML() { + throw new UnsupportedOperationException(); + } + + @Test + @Override + public void testHealthCheckWithCustomNamedQuery() { + ctx.delegate().testHealthCheckWithCustomNamedQuery(); + } + + @Test + @Override + public void testHealthCheckWithCustomQuery() { + ctx.delegate().testHealthCheckWithCustomQuery(); + } +} diff --git a/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBObservabilityRemoteTestIT.java b/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBObservabilityRemoteTestIT.java new file mode 100644 index 00000000000..60de5ff2b46 --- /dev/null +++ b/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBObservabilityRemoteTestIT.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.mongodb; + +import io.helidon.tests.integration.dbclient.common.ObservabilityTest; + +import org.junit.jupiter.api.Test; + +/** + * Remote observability test. + */ +final class MongoDBObservabilityRemoteTestIT extends MongoDBRemoteTest implements ObservabilityTest { + + MongoDBObservabilityRemoteTestIT() { + super("/test/observability"); + } + + @Test + @Override + public void testHttpHealthNoDetails() { + remoteTest(); + } + + @Test + @Override + public void testHttpHealthDetails() { + remoteTest(); + } + + @Test + @Override + public void testHttpMetrics() { + remoteTest(); + } + + @Test + @Override + public void testHealthCheck() { + remoteTest(); + } + + @Test + @Override + public void testHealthCheckWithName() { + remoteTest(); + } + + @Override + @SuppressWarnings("ALL") + public void testHealthCheckWithCustomNamedDML() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testHealthCheckWithCustomDML() { + throw new UnsupportedOperationException(); + } + + @Test + @Override + public void testHealthCheckWithCustomNamedQuery() { + remoteTest(); + } + + @Test + @Override + public void testHealthCheckWithCustomQuery() { + remoteTest(); + } +} diff --git a/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBRemoteTest.java b/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBRemoteTest.java new file mode 100644 index 00000000000..edee87776c3 --- /dev/null +++ b/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBRemoteTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.mongodb; + +import java.nio.file.Path; +import java.util.Map; + +import io.helidon.tests.integration.dbclient.common.RemoteTest; +import io.helidon.tests.integration.harness.ProcessRunner; +import io.helidon.tests.integration.harness.ProcessRunner.ExecMode; +import io.helidon.tests.integration.harness.WaitStrategy; +import io.helidon.tests.integration.harness.TestProcess; +import io.helidon.tests.integration.harness.TestProcesses; + +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +/** + * Base class for the remote tests. + */ +@Testcontainers(disabledWithoutDocker = true) +@TestProcesses +abstract class MongoDBRemoteTest extends RemoteTest { + + @Container + static final GenericContainer CONTAINER = MongoDBTestContainer.CONTAINER; + + @TestProcess + static final ProcessRunner PROCESS_RUNNER = ProcessRunner.of(ExecMode.CLASS_PATH) + .finalName("helidon-tests-integration-dbclient-mongodb") + .properties(Map.of("java.util.logging.config.file", Path.of("target/classes/logging.properties").toAbsolutePath())) + .properties(MongoDBTestContainer::config) + .waitingFor(WaitStrategy.waitForPort()); + + /** + * Create a new instance. + * + * @param path base path + */ + @SuppressWarnings("resource") + MongoDBRemoteTest(String path) { + super(path, PROCESS_RUNNER.process().port()); + } +} diff --git a/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBSimpleLocalTestIT.java b/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBSimpleLocalTestIT.java new file mode 100644 index 00000000000..03f9e69f4c7 --- /dev/null +++ b/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBSimpleLocalTestIT.java @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.mongodb; + +import io.helidon.tests.integration.dbclient.common.LocalTextContext; +import io.helidon.tests.integration.dbclient.common.SimpleTest; +import io.helidon.tests.integration.dbclient.common.SimpleTestImpl; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Local simple test. + */ +final class MongoDBSimpleLocalTestIT extends MongoDBLocalTest implements SimpleTest { + + static LocalTextContext ctx; + + @BeforeAll + static void setUp() { + ctx = context(SimpleTestImpl::new); + } + + @Test + @Override + public void testCreateNamedDeleteStrStrOrderArgs() { + ctx.delegate().testCreateNamedDeleteStrStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedDeleteStrNamedArgs() { + ctx.delegate().testCreateNamedDeleteStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDeleteStrOrderArgs() { + ctx.delegate().testCreateNamedDeleteStrOrderArgs(); + } + + @Test + @Override + public void testCreateDeleteNamedArgs() { + ctx.delegate().testCreateDeleteNamedArgs(); + } + + @Test + @Override + public void testCreateDeleteOrderArgs() { + ctx.delegate().testCreateDeleteOrderArgs(); + } + + @Test + @Override + public void testNamedDeleteOrderArgs() { + ctx.delegate().testNamedDeleteOrderArgs(); + } + + @Test + @Override + public void testDeleteOrderArgs() { + ctx.delegate().testDeleteOrderArgs(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateNamedDmlWithInsertStrStrNamedArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateNamedDmlWithInsertStrNamedArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateNamedDmlWithInsertStrOrderArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateDmlWithInsertNamedArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateDmlWithInsertOrderArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testNamedDmlWithInsertOrderArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testDmlWithInsertOrderArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateNamedDmlWithUpdateStrStrNamedArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateNamedDmlWithUpdateStrNamedArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateNamedDmlWithUpdateStrOrderArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateDmlWithUpdateNamedArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateDmlWithUpdateOrderArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testNamedDmlWithUpdateOrderArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testDmlWithUpdateOrderArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateNamedDmlWithDeleteStrStrOrderArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateNamedDmlWithDeleteStrNamedArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateNamedDmlWithDeleteStrOrderArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateDmlWithDeleteNamedArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateDmlWithDeleteOrderArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testNamedDmlWithDeleteOrderArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testDmlWithDeleteOrderArgs() { + throw new UnsupportedOperationException(); + } + + @Test + @Override + public void testCreateNamedGetStrStrNamedArgs() { + ctx.delegate().testCreateNamedGetStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedGetStrNamedArgs() { + ctx.delegate().testCreateNamedGetStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedGetStrOrderArgs() { + ctx.delegate().testCreateNamedGetStrOrderArgs(); + } + + @Test + @Override + public void testCreateGetNamedArgs() { + ctx.delegate().testCreateGetNamedArgs(); + } + + @Test + @Override + public void testCreateGetOrderArgs() { + ctx.delegate().testCreateGetOrderArgs(); + } + + @Test + @Override + public void testNamedGetStrOrderArgs() { + ctx.delegate().testNamedGetStrOrderArgs(); + } + + @Test + @Override + public void testGetStrOrderArgs() { + ctx.delegate().testGetStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedInsertStrStrNamedArgs() { + ctx.delegate().testCreateNamedInsertStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedInsertStrNamedArgs() { + ctx.delegate().testCreateNamedInsertStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedInsertStrOrderArgs() { + ctx.delegate().testCreateNamedInsertStrOrderArgs(); + } + + @Test + @Override + public void testCreateInsertNamedArgs() { + ctx.delegate().testCreateInsertNamedArgs(); + } + + @Test + @Override + public void testCreateInsertOrderArgs() { + ctx.delegate().testCreateInsertOrderArgs(); + } + + @Test + @Override + public void testNamedInsertOrderArgs() { + ctx.delegate().testNamedInsertOrderArgs(); + } + + @Test + @Override + public void testInsertOrderArgs() { + ctx.delegate().testInsertOrderArgs(); + } + + @Test + @Override + public void testCreateNamedQueryStrStrOrderArgs() { + ctx.delegate().testCreateNamedQueryStrStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedQueryStrNamedArgs() { + ctx.delegate().testCreateNamedQueryStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedQueryStrOrderArgs() { + ctx.delegate().testCreateNamedQueryStrOrderArgs(); + } + + @Test + @Override + public void testCreateQueryNamedArgs() { + ctx.delegate().testCreateQueryNamedArgs(); + } + + @Test + @Override + public void testCreateQueryOrderArgs() { + ctx.delegate().testCreateQueryOrderArgs(); + } + + @Test + @Override + public void testNamedQueryOrderArgs() { + ctx.delegate().testNamedQueryOrderArgs(); + } + + @Test + @Override + public void testQueryOrderArgs() { + ctx.delegate().testQueryOrderArgs(); + } + + @Test + @Override + public void testCreateNamedUpdateStrStrNamedArgs() { + ctx.delegate().testCreateNamedUpdateStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedUpdateStrNamedArgs() { + ctx.delegate().testCreateNamedUpdateStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedUpdateStrOrderArgs() { + ctx.delegate().testCreateNamedUpdateStrOrderArgs(); + } + + @Test + @Override + public void testCreateUpdateNamedArgs() { + ctx.delegate().testCreateUpdateNamedArgs(); + } + + @Test + @Override + public void testCreateUpdateOrderArgs() { + ctx.delegate().testCreateUpdateOrderArgs(); + } + + @Test + @Override + public void testNamedUpdateNamedArgs() { + ctx.delegate().testNamedUpdateNamedArgs(); + } + + @Test + @Override + public void testUpdateOrderArgs() { + ctx.delegate().testUpdateOrderArgs(); + } +} diff --git a/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBSimpleRemoteTestIT.java b/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBSimpleRemoteTestIT.java new file mode 100644 index 00000000000..5f6528cff1a --- /dev/null +++ b/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBSimpleRemoteTestIT.java @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.mongodb; + +import io.helidon.tests.integration.dbclient.common.SimpleTest; + +import org.junit.jupiter.api.Test; + +/** + * Remote simple test. + */ +final class MongoDBSimpleRemoteTestIT extends MongoDBRemoteTest implements SimpleTest { + + MongoDBSimpleRemoteTestIT() { + super("/test/simple"); + } + + @Test + @Override + public void testCreateNamedDeleteStrStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDeleteStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDeleteStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDeleteNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testDeleteOrderArgs() { + remoteTest(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateNamedDmlWithInsertStrStrNamedArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateNamedDmlWithInsertStrNamedArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateNamedDmlWithInsertStrOrderArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateDmlWithInsertNamedArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateDmlWithInsertOrderArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testNamedDmlWithInsertOrderArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testDmlWithInsertOrderArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateNamedDmlWithUpdateStrStrNamedArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateNamedDmlWithUpdateStrNamedArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateNamedDmlWithUpdateStrOrderArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateDmlWithUpdateNamedArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateDmlWithUpdateOrderArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testNamedDmlWithUpdateOrderArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testDmlWithUpdateOrderArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateNamedDmlWithDeleteStrStrOrderArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateNamedDmlWithDeleteStrNamedArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateNamedDmlWithDeleteStrOrderArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateDmlWithDeleteNamedArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testCreateDmlWithDeleteOrderArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testNamedDmlWithDeleteOrderArgs() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testDmlWithDeleteOrderArgs() { + throw new UnsupportedOperationException(); + } + + @Test + @Override + public void testCreateNamedGetStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedGetStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedGetStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateGetNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateGetOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedGetStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testGetStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedInsertStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedInsertStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedInsertStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateInsertNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryStrStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateQueryNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateQueryOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedQueryOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testQueryOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedUpdateStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedUpdateStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedUpdateStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateUpdateNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateUpdateOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedUpdateNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testUpdateOrderArgs() { + remoteTest(); + } +} diff --git a/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBStatementLocalTestIT.java b/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBStatementLocalTestIT.java new file mode 100644 index 00000000000..21eed9ea716 --- /dev/null +++ b/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBStatementLocalTestIT.java @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.mongodb; + +import io.helidon.tests.integration.dbclient.common.LocalTextContext; +import io.helidon.tests.integration.dbclient.common.StatementTest; +import io.helidon.tests.integration.dbclient.common.StatementTestImpl; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Local statement test. + */ +final class MongoDBStatementLocalTestIT extends MongoDBLocalTest implements StatementTest { + + static LocalTextContext ctx; + + @BeforeAll + static void setUp() { + ctx = context(StatementTestImpl::new); + } + + @Test + @Override + public void testCreateNamedQueryNonExistentStmt() { + ctx.delegate().testCreateNamedQueryNonExistentStmt(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithoutArgs() { + ctx.delegate().testCreateNamedQueryNamedAndOrderArgsWithoutArgs(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithArgs() { + ctx.delegate().testCreateNamedQueryNamedAndOrderArgsWithArgs(); + } + + @Test + @Override + public void testCreateNamedQueryNamedArgsSetOrderArg() { + ctx.delegate().testCreateNamedQueryNamedArgsSetOrderArg(); + } + + @Test + @Override + public void testCreateNamedQueryOrderArgsSetNamedArg() { + ctx.delegate().testCreateNamedQueryOrderArgsSetNamedArg(); + } + + @Test + @Override + public void testGetArrayParams() { + ctx.delegate().testGetArrayParams(); + } + + @Test + @Override + public void testGetListParams() { + ctx.delegate().testGetListParams(); + } + + @Test + @Override + public void testGetMapParams() { + ctx.delegate().testGetMapParams(); + } + + @Test + @Override + public void testGetOrderParam() { + ctx.delegate().testGetOrderParam(); + } + + @Test + @Override + public void testGetNamedParam() { + ctx.delegate().testGetNamedParam(); + } + + @Test + @Override + public void testGetMappedNamedParam() { + ctx.delegate().testGetMappedNamedParam(); + } + + @Test + @Override + public void testGetMappedOrderParam() { + ctx.delegate().testGetMappedOrderParam(); + } + + @Test + @Override + public void testQueryArrayParams() { + ctx.delegate().testQueryArrayParams(); + } + + @Test + @Override + public void testQueryListParams() { + ctx.delegate().testQueryListParams(); + } + + @Test + @Override + public void testQueryMapParams() { + ctx.delegate().testQueryMapParams(); + } + + @Test + @Override + public void testQueryOrderParam() { + ctx.delegate().testQueryOrderParam(); + } + + @Test + @Override + public void testQueryNamedParam() { + ctx.delegate().testQueryNamedParam(); + } + + @Test + @Override + public void testQueryMappedNamedParam() { + ctx.delegate().testQueryMappedNamedParam(); + } + + @Test + @Override + public void testQueryMappedOrderParam() { + ctx.delegate().testQueryMappedOrderParam(); + } + + @Override + @SuppressWarnings("ALL") + public void testQueryMapMissingParams() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testDmlArrayParams() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testDmlListParams() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testDmlMapParams() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testDmlOrderParam() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testDmlNamedParam() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testDmlMappedNamedParam() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testDmlMappedOrderParam() { + throw new UnsupportedOperationException(); + } +} diff --git a/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBStatementRemoteTestIT.java b/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBStatementRemoteTestIT.java new file mode 100644 index 00000000000..3d5b68d1b4c --- /dev/null +++ b/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBStatementRemoteTestIT.java @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.mongodb; + +import io.helidon.tests.integration.dbclient.common.StatementTest; + +import org.junit.jupiter.api.Test; + +/** + * Remote statement test. + */ +final class MongoDBStatementRemoteTestIT extends MongoDBRemoteTest implements StatementTest { + + MongoDBStatementRemoteTestIT() { + super("/test/statement"); + } + + @Test + @Override + public void testCreateNamedQueryNonExistentStmt() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithoutArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNamedArgsSetOrderArg() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryOrderArgsSetNamedArg() { + remoteTest(); + } + + @Test + @Override + public void testGetArrayParams() { + remoteTest(); + } + + @Test + @Override + public void testGetListParams() { + remoteTest(); + } + + @Test + @Override + public void testGetMapParams() { + remoteTest(); + } + + @Test + @Override + public void testGetOrderParam() { + remoteTest(); + } + + @Test + @Override + public void testGetNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testGetMappedNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testGetMappedOrderParam() { + remoteTest(); + } + + @Test + @Override + public void testQueryArrayParams() { + remoteTest(); + } + + @Test + @Override + public void testQueryListParams() { + remoteTest(); + } + + @Test + @Override + public void testQueryMapParams() { + remoteTest(); + } + + @Test + @Override + public void testQueryOrderParam() { + remoteTest(); + } + + @Test + @Override + public void testQueryNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testQueryMappedNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testQueryMappedOrderParam() { + remoteTest(); + } + + @Override + @SuppressWarnings("ALL") + public void testQueryMapMissingParams() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testDmlArrayParams() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testDmlListParams() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testDmlMapParams() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testDmlOrderParam() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testDmlNamedParam() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testDmlMappedNamedParam() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testDmlMappedOrderParam() { + throw new UnsupportedOperationException(); + } +} diff --git a/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBSuiteIT.java b/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBSuiteIT.java deleted file mode 100644 index de2c0467341..00000000000 --- a/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBSuiteIT.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (c) 2023 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.tests.integration.dbclient.mongodb; - -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Stream; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.dbclient.DbClient; -import io.helidon.dbclient.DbExecute; -import io.helidon.dbclient.DbRow; -import io.helidon.tests.integration.dbclient.common.model.Pokemon; -import io.helidon.tests.integration.dbclient.common.model.Type; -import io.helidon.tests.integration.dbclient.common.utils.TestConfig; -import io.helidon.tests.integration.dbclient.common.tests.MapperIT; - -import io.helidon.tests.integration.harness.AfterSuite; -import io.helidon.tests.integration.harness.BeforeSuite; -import org.junit.platform.suite.api.ExcludeClassNamePatterns; -import org.junit.platform.suite.api.IncludeClassNamePatterns; -import org.junit.platform.suite.api.SelectPackages; -import org.junit.platform.suite.api.Suite; - -import static io.helidon.tests.integration.dbclient.common.model.Pokemon.POKEMONS; -import static io.helidon.tests.integration.dbclient.common.model.Type.TYPES; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.empty; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; - -/** - * Test Database Client MongoDB. - */ -@Suite -@SelectPackages("io.helidon.tests.integration.dbclient.common.tests") -@ExcludeClassNamePatterns(".*Transaction.*") -@IncludeClassNamePatterns(".*IT") -class MongoDBSuiteIT { - - private static final System.Logger LOGGER = System.getLogger(MapperIT.class.getName()); - private static final int TIMEOUT = 60; - - @BeforeSuite - static Map setup() { - Config config = Config.create(ConfigSources.classpath(TestConfig.configFile())); - DbClient dbClient = DbClient.builder(config.get("db")).build(); - waitForStart(dbClient); - ping(dbClient); - initSchema(dbClient); - initData(dbClient); - testListTypes(dbClient); - testListPokemons(dbClient); - testListPokemonTypes(dbClient); - return Map.of("dbClient", dbClient); - } - - @AfterSuite - static void tearDown(DbClient dbClient) { - deleteSchema(dbClient); - testDeletedSchema(dbClient); - } - - private static void ping(DbClient dbClient) { - DbExecute exec = dbClient.execute(); - DbRow row = exec.namedQuery("ping-query").findFirst().orElseThrow(); - Double ok = row.column("ok").as(Double.class); - assertThat(ok, equalTo(1.0)); - LOGGER.log(System.Logger.Level.DEBUG, () -> String.format("Command ping row: %s", row)); - } - - private static void initSchema(DbClient dbClient) { - DbExecute exec = dbClient.execute(); - exec.namedDml("create-types"); - exec.namedDml("create-pokemons"); - exec.namedDml("create-poketypes"); - } - - private static void initData(DbClient dbClient) { - DbExecute exec = dbClient.execute(); - long count = 0; - for (Map.Entry entry : TYPES.entrySet()) { - count += exec.namedInsert("insert-type", entry.getKey(), entry.getValue().name()); - } - - for (Map.Entry entry : POKEMONS.entrySet()) { - count += exec.namedInsert("insert-pokemon", entry.getKey(), entry.getValue().getName()); - } - - for (Map.Entry entry : POKEMONS.entrySet()) { - Pokemon pokemon = entry.getValue(); - for (Type type : pokemon.getTypes()) { - count += exec.namedInsert("insert-poketype", pokemon.getId(), type.id()); - } - } - LOGGER.log(System.Logger.Level.INFO, String.format("executed %s statements", count)); - } - - private static void testListTypes(DbClient dbClient) { - DbExecute exec = dbClient.execute(); - - List rows = exec.namedQuery("select-types").toList(); - assertThat(rows, not(empty())); - - Set ids = new HashSet<>(TYPES.keySet()); - for (DbRow row : rows) { - Integer id = row.column(1).as(Integer.class); - String name = row.column(2).as(String.class); - assertThat(ids, hasItem(id)); - assertThat(name, TYPES.get(id).name().equals(name)); - } - } - - private static void testListPokemons(DbClient dbClient) { - DbExecute exec = dbClient.execute(); - - List rowsList = exec.namedQuery("select-pokemons").toList(); - assertThat(rowsList, not(empty())); - - Set ids = new HashSet<>(POKEMONS.keySet()); - for (DbRow row : rowsList) { - Integer id = row.column(1).as(Integer.class); - String name = row.column(2).as(String.class); - assertThat(ids, hasItem(id)); - assertThat(name, POKEMONS.get(id).getName().equals(name)); - } - } - - private static void testListPokemonTypes(DbClient dbClient) { - DbExecute exec = dbClient.execute(); - - List rows = exec.namedQuery("select-pokemons").toList(); - assertThat(rows, not(empty())); - - for (DbRow row : rows) { - Integer pokemonId = row.column(1).as(Integer.class); - String pokemonName = row.column(2).as(String.class); - Pokemon pokemon = POKEMONS.get(pokemonId); - assertThat(pokemonName, POKEMONS.get(pokemonId).getName().equals(pokemonName)); - Stream typeRows = exec.namedQuery("select-poketypes", pokemonId); - - List typeRowsList = typeRows.toList(); - assertThat(typeRowsList.size(), equalTo(pokemon.getTypes().size())); - for (DbRow typeRow : typeRowsList) { - Integer typeId = typeRow.column(2).as(Integer.class); - assertThat(pokemon.getTypes(), hasItem(TYPES.get(typeId))); - } - } - } - - private static void deleteSchema(DbClient dbClient) { - DbExecute exec = dbClient.execute(); - exec.namedDelete("delete-poketypes"); - exec.namedDelete("delete-pokemons"); - exec.namedDelete("delete-types"); - } - - private static void testDeletedSchema(DbClient dbClient) { - DbExecute exec = dbClient.execute(); - assertThat(exec.namedQuery("select-types").count(), is(0)); - assertThat(exec.namedQuery("select-pokemons").count(), is(0)); - assertThat(exec.namedQuery("select-pokemons-all").count(), is(0)); - } - - @SuppressWarnings("BusyWait") - private static void waitForStart(DbClient dbClient) { - long endTm = 1000 * TIMEOUT + System.currentTimeMillis(); - while (true) { - try { - dbClient.execute().namedGet("ping"); - break; - } catch (Throwable th) { - if (System.currentTimeMillis() > endTm) { - throw new IllegalStateException("Database startup failed!", th); - } - LOGGER.log(System.Logger.Level.DEBUG, () -> String.format("Exception: %s", th.getMessage()), th); - try { - Thread.sleep(1000); - } catch (InterruptedException ignored) { - } - } - } - } -} diff --git a/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBTestContainer.java b/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBTestContainer.java new file mode 100644 index 00000000000..c5418d11d4a --- /dev/null +++ b/tests/integration/dbclient/mongodb/src/test/java/io/helidon/tests/integration/dbclient/mongodb/MongoDBTestContainer.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.mongodb; + +import java.nio.file.Path; +import java.time.Duration; +import java.util.Map; +import java.util.function.Supplier; + +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.images.builder.ImageFromDockerfile; + +/** + * Database container utility. + */ +abstract class MongoDBTestContainer { + + private static final ImageFromDockerfile IMAGE = new ImageFromDockerfile("mongodb", false) + .withFileFromPath(".", Path.of("etc/docker")); + + static final GenericContainer CONTAINER = new GenericContainer<>(IMAGE) + .withEnv("MONGO_DB", "pokemon") + .withEnv("MONGO_USER", "test") + .withEnv("MONGO_PASSWORD", "mongo123") + .withExposedPorts(27017) + .waitingFor(Wait.forLogMessage("\\s*Container ready!\\s*", 1) + .withStartupTimeout(Duration.ofMinutes(1))); + + static Map> config() { + return Map.of("db.connection.url", MongoDBTestContainer::connectionString); + } + + static String connectionString() { + return "mongodb://localhost:%s/pokemon".formatted(CONTAINER.getMappedPort(27017)); + } + + private MongoDBTestContainer() { + } +} diff --git a/tests/integration/dbclient/mongodb/src/test/resources/test.yaml b/tests/integration/dbclient/mongodb/src/test/resources/test.yaml deleted file mode 100644 index 14e502fa6c1..00000000000 --- a/tests/integration/dbclient/mongodb/src/test/resources/test.yaml +++ /dev/null @@ -1,206 +0,0 @@ -# -# Copyright (c) 2019, 2023 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. -# - -dbadmin: - source: mongoDb - connection: - url: mongodb://${mongo.host}:${mongo.port}/admin - username: ${mongo.root-user} - password: ${mongo.root-password} - statements: - ping: '{ - "operation": "command", - "query": { ping: 1 } - }' - use: '{ - "operation": "command", - "query": { use: "${mongo.database}" } - }' - create-user: '{ - "operation": "command", - "query": { - "createUser": "${mongo.user}", - "pwd": "${mongo.password}", - "roles": [ - { role: "readWrite", db: "${mongo.database}" } - ] - } - }' - -db: - source: mongoDb - connection: - url: mongodb://${mongo.host}:${mongo.port}/${mongo.database} - username: ${mongo.user} - password: ${mongo.password} - - health-check: - type: query - statement: '{ - "operation": "command", - "query": { ping: 1 } - }' - - statements: - ping-query: '{ - "operation": "command", - "query": { ping: 1 } - }' - delete-types: '{ - "collection": "types", - "operation": "delete", - "query": { } - }' - delete-pokemons: '{ - "collection": "pokemons", - "operation": "delete", - "query": { } - }' - delete-poketypes: '{ - "collection": "pokemon_types", - "operation": "delete", - "query": { } - }' - insert-type: '{ - "collection": "types", - "value": { - "id": ?, - "type": ? - } - }' - insert-pokemon: '{ - "collection": "pokemons", - "value": { - "id": ?, - "name": ? - } - }' - insert-poketype: '{ - "collection": "pokemon_types", - "value": { - "id_pokemon": ?, - "id_type": ? - } - }' - select-types: '{ - "collection": "types", - "projection": { id: 1, type: 1, _id: 0 }, - "query": {} - }' - select-pokemons: '{ - "collection": "pokemons", - "projection": { id: 1, name: 1, _id: 0 }, - "query": {} - }' - select-poketypes: '{ - "collection": "pokemon_types", - "projection": { id_pokemon: 1, id_type: 1, _id: 0 }, - "query": { id_pokemon: ? } - }' - select-poketypes-all: '{ - "collection": "pokemon_types", - "projection": { id_pokemon: 1, id_type: 1, _id: 0 }, - "query": {} - }' - select-pokemon-named-arg: '{ - "collection": "pokemons", - "operation": "query", - "projection": { id: 1, name: 1, _id: 0 }, - "query": { name: $name } - }' - select-pokemon-order-arg: '{ - "collection": "pokemons", - "operation": "query", - "projection": { id: 1, name: 1, _id: 0 }, - "query": { name: ? } - }' - insert-pokemon-named-arg: '{ - "collection": "pokemons", - "operation": "insert", - "value": { - "id": $id, - "name": $name - } - }' - insert-pokemon-order-arg: '{ - "collection": "pokemons", - "operation": "insert", - "value": { - "id": ?, - "name": ? - } - }' - insert-pokemon-order-arg-rev: '{ - "collection": "pokemons", - "operation": "insert", - "value": { - "name": ?, - "id": ? - } - }' - select-pokemon-by-id: '{ - "collection": "pokemons", - "operation": "query", - "projection": { id: 1, name: 1, _id: 0 }, - "query": { id: ? } - }' - update-pokemon-named-arg: '{ - "collection": "pokemons", - "operation": "update", - "value":{ $set: { "name": $name } }, - "query": { id: $id } - }' - update-pokemon-order-arg: '{ - "collection": "pokemons", - "operation": "update", - "value":{ $set: { "name": ? } }, - "query": { id: ? } - }' - delete-pokemon-named-arg: '{ - "collection": "pokemons", - "operation": "delete", - "query": { id: $id } - }' - delete-pokemon-order-arg: '{ - "collection": "pokemons", - "operation": "delete", - "query": { id: ? } - }' - delete-pokemon-full-named-arg: '{ - "collection": "pokemons", - "operation": "delete", - "query": { $and: [ {name: $name }, { id: $id } ] } - }' - delete-pokemon-full-order-arg: '{ - "collection": "pokemons", - "operation": "delete", - "query": { $and: [ {name: ? }, { id: ? } ] } - }' - select-pokemons-idrng-named-arg: '{ - "collection": "pokemons", - "operation": "query", - "projection": { id: 1, name: 1, _id: 0 }, - "query": { $and: [ { id: { $gt: $idmin } }, { id: { $lt: $idmax } } ] } - }' - select-pokemons-idrng-order-arg: '{ - "collection": "pokemons", - "operation": "query", - "projection": { id: 1, name: 1, _id: 0 }, - "query": { $and: [ { id: { $gt: ? } }, { id: { $lt: ? } } ] } - }' - -test: - ping-dml: false diff --git a/tests/integration/dbclient/mysql/README.md b/tests/integration/dbclient/mysql/README.md new file mode 100644 index 00000000000..5f5f4e26e80 --- /dev/null +++ b/tests/integration/dbclient/mysql/README.md @@ -0,0 +1,17 @@ +# DbClient Integration Test MySQL + +To run this test: +```shell +mvn clean verify +``` + +Start the database: +```shell +docker run -d \ + --name mysql \ + -e MYSQL_DATABASE=test \ + -e MYSQL_USER=test \ + -e MYSQL_PASSWORD=mysql123 \ + -p 3306:3306 \ + container-registry.oracle.com/mysql/community-server:latest +``` diff --git a/tests/integration/dbclient/mysql/pom.xml b/tests/integration/dbclient/mysql/pom.xml new file mode 100644 index 00000000000..de3440248ae --- /dev/null +++ b/tests/integration/dbclient/mysql/pom.xml @@ -0,0 +1,80 @@ + + + + + 4.0.0 + + io.helidon.tests.integration.dbclient + helidon-tests-integration-dbclient-parent + 4.1.0-SNAPSHOT + ../parent/pom.xml + + helidon-tests-integration-dbclient-mysql + Helidon Tests Integration DbClient MySQL + + + + io.helidon.dbclient + helidon-dbclient-jdbc + + + io.helidon.dbclient + helidon-dbclient-metrics-hikari + + + io.helidon.integrations.db + helidon-integrations-db-mysql + + + com.mysql + mysql-connector-j + + + org.testcontainers + mysql + test + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-libs + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + integration-test + verify + + + + + + + diff --git a/tests/integration/dbclient/mysql/src/main/resources/db.yaml b/tests/integration/dbclient/mysql/src/main/resources/db.yaml new file mode 100644 index 00000000000..68f85b365e8 --- /dev/null +++ b/tests/integration/dbclient/mysql/src/main/resources/db.yaml @@ -0,0 +1,30 @@ +# +# Copyright (c) 2024 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. +# + +db: + source: jdbc + connection: + url: jdbc:mysql://localhost:3306/test?useSSL=false&allowPublicKeyRetrieval=true + username: test + password: mysql123 + poolName: test + initializationFailTimeout: -1 + connectionTimeout: 2000 + health-check: + type: query + statement: "SELECT 0" + statements: + ping-dml: "DO 0" diff --git a/tests/integration/dbclient/mysql/src/main/resources/logging.properties b/tests/integration/dbclient/mysql/src/main/resources/logging.properties new file mode 100644 index 00000000000..d590b197673 --- /dev/null +++ b/tests/integration/dbclient/mysql/src/main/resources/logging.properties @@ -0,0 +1,18 @@ +# +# Copyright (c) 2024 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. +# + +handlers=org.slf4j.bridge.SLF4JBridgeHandler +.level=INFO diff --git a/tests/integration/dbclient/mysql/src/main/resources/simplelogger.properties b/tests/integration/dbclient/mysql/src/main/resources/simplelogger.properties new file mode 100644 index 00000000000..fcc605df165 --- /dev/null +++ b/tests/integration/dbclient/mysql/src/main/resources/simplelogger.properties @@ -0,0 +1,22 @@ +# +# Copyright (c) 2024 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. +# +org.slf4j.simpleLogger.defaultLogLevel=warn +org.slf4j.simpleLogger.showThreadName=false +org.slf4j.simpleLogger.log.org.testcontainers=info +org.slf4j.simpleLogger.log.org.testcontainers.utility=error +org.slf4j.simpleLogger.log.io.helidon=info +org.slf4j.simpleLogger.log.org.hibernate=info +org.slf4j.simpleLogger.log.com.zaxxer=info diff --git a/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLLocalTest.java b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLLocalTest.java new file mode 100644 index 00000000000..1a18268b159 --- /dev/null +++ b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLLocalTest.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.mysql; + +import java.util.function.BiFunction; + +import io.helidon.config.Config; +import io.helidon.dbclient.DbClient; +import io.helidon.tests.integration.dbclient.common.LocalTextContext; + +import org.testcontainers.containers.MySQLContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +/** + * Base class for the local tests. + */ +@Testcontainers(disabledWithoutDocker = true) +abstract class MySQLLocalTest { + + @Container + static final MySQLContainer CONTAINER = MySQLTestContainer.CONTAINER; + + static LocalTextContext context(BiFunction factory) { + return LocalTextContext.create(factory, MySQLTestContainer.config(), true); + } +} diff --git a/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLMiscLocalTestIT.java b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLMiscLocalTestIT.java new file mode 100644 index 00000000000..18cabc1c554 --- /dev/null +++ b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLMiscLocalTestIT.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.mysql; + +import io.helidon.tests.integration.dbclient.common.LocalTextContext; +import io.helidon.tests.integration.dbclient.common.MiscTest; +import io.helidon.tests.integration.dbclient.common.MiscTestImpl; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Local misc test. + */ +final class MySQLMiscLocalTestIT extends MySQLLocalTest implements MiscTest { + + static LocalTextContext ctx; + + @BeforeAll + static void setUp() { + ctx = context(MiscTestImpl::new); + } + + @Test + @Override + public void testFlowControl() { + ctx.delegate().testFlowControl(); + } + + @Test + @Override + public void testStatementInterceptor() { + ctx.delegate().testStatementInterceptor(); + } + + @Test + @Override + public void testInsertWithOrderMapping() { + ctx.delegate().testInsertWithOrderMapping(); + } + + @Test + @Override + public void testInsertWithNamedMapping() { + ctx.delegate().testInsertWithNamedMapping(); + } + + @Test + @Override + public void testUpdateWithOrderMapping() { + ctx.delegate().testUpdateWithOrderMapping(); + } + + @Test + @Override + public void testUpdateWithNamedMapping() { + ctx.delegate().testUpdateWithNamedMapping(); + } + + @Test + @Override + public void testDeleteWithOrderMapping() { + ctx.delegate().testDeleteWithOrderMapping(); + } + + @Test + @Override + public void testDeleteWithNamedMapping() { + ctx.delegate().testDeleteWithNamedMapping(); + } + + @Test + @Override + public void testQueryWithMapping() { + ctx.delegate().testQueryWithMapping(); + } + + @Test + @Override + public void testGetWithMapping() { + ctx.delegate().testGetWithMapping(); + } +} diff --git a/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLMiscRemoteTestIT.java b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLMiscRemoteTestIT.java new file mode 100644 index 00000000000..9b249af97b3 --- /dev/null +++ b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLMiscRemoteTestIT.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.mysql; + +import io.helidon.tests.integration.dbclient.common.MiscTest; + +import org.junit.jupiter.api.Test; + +/** + * Remote misc test. + */ +final class MySQLMiscRemoteTestIT extends MySQLRemoteTest implements MiscTest { + + MySQLMiscRemoteTestIT() { + super("/test/misc"); + } + + @Test + @Override + public void testFlowControl() { + remoteTest(); + } + + @Test + @Override + public void testStatementInterceptor() { + remoteTest(); + } + + @Test + @Override + public void testInsertWithOrderMapping() { + remoteTest(); + } + + @Test + @Override + public void testInsertWithNamedMapping() { + remoteTest(); + } + + @Test + @Override + public void testUpdateWithOrderMapping() { + remoteTest(); + } + + @Test + @Override + public void testUpdateWithNamedMapping() { + remoteTest(); + } + + @Test + @Override + public void testDeleteWithOrderMapping() { + remoteTest(); + } + + @Test + @Override + public void testDeleteWithNamedMapping() { + remoteTest(); + } + + @Test + @Override + public void testQueryWithMapping() { + remoteTest(); + } + + @Test + @Override + public void testGetWithMapping() { + remoteTest(); + } +} diff --git a/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLObservabilityLocalTestIT.java b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLObservabilityLocalTestIT.java new file mode 100644 index 00000000000..64ec9582e8e --- /dev/null +++ b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLObservabilityLocalTestIT.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.mysql; + +import io.helidon.tests.integration.dbclient.common.DbClientITMain; +import io.helidon.tests.integration.dbclient.common.LocalTextContext; +import io.helidon.tests.integration.dbclient.common.ObservabilityTest; +import io.helidon.tests.integration.dbclient.common.ObservabilityTestImpl; +import io.helidon.webclient.http1.Http1Client; +import io.helidon.webserver.WebServerConfig; +import io.helidon.webserver.testing.junit5.ServerTest; +import io.helidon.webserver.testing.junit5.SetUpServer; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Local observability test. + */ +@ServerTest +final class MySQLObservabilityLocalTestIT extends MySQLLocalTest implements ObservabilityTest { + + private static Http1Client client; + private static LocalTextContext ctx; + + @BeforeAll + static void beforeAll(Http1Client aClient) { + client = aClient; + } + + @SetUpServer + static void setUp(WebServerConfig.Builder builder) { + ctx = context((db, c) -> new ObservabilityTestImpl(db, c, () -> client)); + DbClientITMain.setup(ctx.db(), ctx.config(), builder); + } + + @Test + @Override + public void testHttpHealthNoDetails() { + ctx.delegate().testHttpHealthNoDetails(); + } + + @Test + @Override + public void testHttpHealthDetails() { + ctx.delegate().testHttpHealthDetails(); + } + + @Test + @Override + public void testHttpMetrics() { + ctx.delegate().testHttpMetrics(); + } + + @Test + @Override + public void testHealthCheck() { + ctx.delegate().testHealthCheck(); + } + + @Test + @Override + public void testHealthCheckWithName() { + ctx.delegate().testHealthCheckWithName(); + } + + @Test + @Override + public void testHealthCheckWithCustomNamedDML() { + ctx.delegate().testHealthCheckWithCustomNamedDML(); + } + + @Test + @Override + public void testHealthCheckWithCustomDML() { + ctx.delegate().testHealthCheckWithCustomDML(); + } + + @Test + @Override + public void testHealthCheckWithCustomNamedQuery() { + ctx.delegate().testHealthCheckWithCustomNamedQuery(); + } + + @Test + @Override + public void testHealthCheckWithCustomQuery() { + ctx.delegate().testHealthCheckWithCustomQuery(); + } +} diff --git a/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLObservabilityRemoteTestIT.java b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLObservabilityRemoteTestIT.java new file mode 100644 index 00000000000..92465e9ac79 --- /dev/null +++ b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLObservabilityRemoteTestIT.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.mysql; + +import io.helidon.tests.integration.dbclient.common.ObservabilityTest; + +import org.junit.jupiter.api.Test; + +/** + * Remote observability test. + */ +final class MySQLObservabilityRemoteTestIT extends MySQLRemoteTest implements ObservabilityTest { + + MySQLObservabilityRemoteTestIT() { + super("/test/observability"); + } + + @Test + @Override + public void testHttpHealthNoDetails() { + remoteTest(); + } + + @Test + @Override + public void testHttpHealthDetails() { + remoteTest(); + } + + @Test + @Override + public void testHttpMetrics() { + remoteTest(); + } + + @Test + @Override + public void testHealthCheck() { + remoteTest(); + } + + @Test + @Override + public void testHealthCheckWithName() { + remoteTest(); + } + + @Test + @Override + public void testHealthCheckWithCustomNamedDML() { + remoteTest(); + } + + @Test + @Override + public void testHealthCheckWithCustomDML() { + remoteTest(); + } + + @Test + @Override + public void testHealthCheckWithCustomNamedQuery() { + remoteTest(); + } + + @Test + @Override + public void testHealthCheckWithCustomQuery() { + remoteTest(); + } +} diff --git a/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLRemoteTest.java b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLRemoteTest.java new file mode 100644 index 00000000000..0efb21ffc8e --- /dev/null +++ b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLRemoteTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.mysql; + +import java.nio.file.Path; +import java.util.Map; + +import io.helidon.tests.integration.dbclient.common.RemoteTest; +import io.helidon.tests.integration.harness.ProcessRunner; +import io.helidon.tests.integration.harness.ProcessRunner.ExecMode; +import io.helidon.tests.integration.harness.WaitStrategy; +import io.helidon.tests.integration.harness.TestProcess; +import io.helidon.tests.integration.harness.TestProcesses; + +import org.testcontainers.containers.MySQLContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +/** + * Base class for the remote tests. + */ +@Testcontainers(disabledWithoutDocker = true) +@TestProcesses +abstract class MySQLRemoteTest extends RemoteTest { + + @Container + static final MySQLContainer CONTAINER = MySQLTestContainer.CONTAINER; + + @TestProcess + static final ProcessRunner PROCESS_RUNNER = ProcessRunner.of(ExecMode.CLASS_PATH) + .finalName("helidon-tests-integration-dbclient-mysql") + .properties(Map.of("java.util.logging.config.file", Path.of("target/classes/logging.properties").toAbsolutePath())) + .properties(MySQLTestContainer::config) + .waitingFor(WaitStrategy.waitForPort()); + + /** + * Create a new instance. + * + * @param path base path + */ + @SuppressWarnings("resource") + MySQLRemoteTest(String path) { + super(path, PROCESS_RUNNER.process().port()); + } +} diff --git a/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLSimpleLocalTestIT.java b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLSimpleLocalTestIT.java new file mode 100644 index 00000000000..c720de50a7b --- /dev/null +++ b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLSimpleLocalTestIT.java @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.mysql; + +import io.helidon.tests.integration.dbclient.common.LocalTextContext; +import io.helidon.tests.integration.dbclient.common.SimpleTest; +import io.helidon.tests.integration.dbclient.common.SimpleTestImpl; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Local simple test. + */ +final class MySQLSimpleLocalTestIT extends MySQLLocalTest implements SimpleTest { + + static LocalTextContext ctx; + + @BeforeAll + static void setUp() { + ctx = context(SimpleTestImpl::new); + } + + @Test + @Override + public void testCreateNamedDeleteStrStrOrderArgs() { + ctx.delegate().testCreateNamedDeleteStrStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedDeleteStrNamedArgs() { + ctx.delegate().testCreateNamedDeleteStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDeleteStrOrderArgs() { + ctx.delegate().testCreateNamedDeleteStrOrderArgs(); + } + + @Test + @Override + public void testCreateDeleteNamedArgs() { + ctx.delegate().testCreateDeleteNamedArgs(); + } + + @Test + @Override + public void testCreateDeleteOrderArgs() { + ctx.delegate().testCreateDeleteOrderArgs(); + } + + @Test + @Override + public void testNamedDeleteOrderArgs() { + ctx.delegate().testNamedDeleteOrderArgs(); + } + + @Test + @Override + public void testDeleteOrderArgs() { + ctx.delegate().testDeleteOrderArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithInsertStrStrNamedArgs() { + ctx.delegate().testCreateNamedDmlWithInsertStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithInsertStrNamedArgs() { + ctx.delegate().testCreateNamedDmlWithInsertStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithInsertStrOrderArgs() { + ctx.delegate().testCreateNamedDmlWithInsertStrOrderArgs(); + } + + @Test + @Override + public void testCreateDmlWithInsertNamedArgs() { + ctx.delegate().testCreateDmlWithInsertNamedArgs(); + } + + @Test + @Override + public void testCreateDmlWithInsertOrderArgs() { + ctx.delegate().testCreateDmlWithInsertOrderArgs(); + } + + @Test + @Override + public void testNamedDmlWithInsertOrderArgs() { + ctx.delegate().testNamedDmlWithInsertOrderArgs(); + } + + @Test + @Override + public void testDmlWithInsertOrderArgs() { + ctx.delegate().testDmlWithInsertOrderArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithUpdateStrStrNamedArgs() { + ctx.delegate().testCreateNamedDmlWithUpdateStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithUpdateStrNamedArgs() { + ctx.delegate().testCreateNamedDmlWithUpdateStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithUpdateStrOrderArgs() { + ctx.delegate().testCreateNamedDmlWithUpdateStrOrderArgs(); + } + + @Test + @Override + public void testCreateDmlWithUpdateNamedArgs() { + ctx.delegate().testCreateDmlWithUpdateNamedArgs(); + } + + @Test + @Override + public void testCreateDmlWithUpdateOrderArgs() { + ctx.delegate().testCreateDmlWithUpdateOrderArgs(); + } + + @Test + @Override + public void testNamedDmlWithUpdateOrderArgs() { + ctx.delegate().testNamedDmlWithUpdateOrderArgs(); + } + + @Test + @Override + public void testDmlWithUpdateOrderArgs() { + ctx.delegate().testDmlWithUpdateOrderArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithDeleteStrStrOrderArgs() { + ctx.delegate().testCreateNamedDmlWithDeleteStrStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithDeleteStrNamedArgs() { + ctx.delegate().testCreateNamedDmlWithDeleteStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithDeleteStrOrderArgs() { + ctx.delegate().testCreateNamedDmlWithDeleteStrOrderArgs(); + } + + @Test + @Override + public void testCreateDmlWithDeleteNamedArgs() { + ctx.delegate().testCreateDmlWithDeleteNamedArgs(); + } + + @Test + @Override + public void testCreateDmlWithDeleteOrderArgs() { + ctx.delegate().testCreateDmlWithDeleteOrderArgs(); + } + + @Test + @Override + public void testNamedDmlWithDeleteOrderArgs() { + ctx.delegate().testNamedDmlWithDeleteOrderArgs(); + } + + @Test + @Override + public void testDmlWithDeleteOrderArgs() { + ctx.delegate().testDmlWithDeleteOrderArgs(); + } + + @Test + @Override + public void testCreateNamedGetStrStrNamedArgs() { + ctx.delegate().testCreateNamedGetStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedGetStrNamedArgs() { + ctx.delegate().testCreateNamedGetStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedGetStrOrderArgs() { + ctx.delegate().testCreateNamedGetStrOrderArgs(); + } + + @Test + @Override + public void testCreateGetNamedArgs() { + ctx.delegate().testCreateGetNamedArgs(); + } + + @Test + @Override + public void testCreateGetOrderArgs() { + ctx.delegate().testCreateGetOrderArgs(); + } + + @Test + @Override + public void testNamedGetStrOrderArgs() { + ctx.delegate().testNamedGetStrOrderArgs(); + } + + @Test + @Override + public void testGetStrOrderArgs() { + ctx.delegate().testGetStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedInsertStrStrNamedArgs() { + ctx.delegate().testCreateNamedInsertStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedInsertStrNamedArgs() { + ctx.delegate().testCreateNamedInsertStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedInsertStrOrderArgs() { + ctx.delegate().testCreateNamedInsertStrOrderArgs(); + } + + @Test + @Override + public void testCreateInsertNamedArgs() { + ctx.delegate().testCreateInsertNamedArgs(); + } + + @Test + @Override + public void testCreateInsertOrderArgs() { + ctx.delegate().testCreateInsertOrderArgs(); + } + + @Test + @Override + public void testNamedInsertOrderArgs() { + ctx.delegate().testNamedInsertOrderArgs(); + } + + @Test + @Override + public void testInsertOrderArgs() { + ctx.delegate().testInsertOrderArgs(); + } + + @Test + @Override + public void testCreateNamedQueryStrStrOrderArgs() { + ctx.delegate().testCreateNamedQueryStrStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedQueryStrNamedArgs() { + ctx.delegate().testCreateNamedQueryStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedQueryStrOrderArgs() { + ctx.delegate().testCreateNamedQueryStrOrderArgs(); + } + + @Test + @Override + public void testCreateQueryNamedArgs() { + ctx.delegate().testCreateQueryNamedArgs(); + } + + @Test + @Override + public void testCreateQueryOrderArgs() { + ctx.delegate().testCreateQueryOrderArgs(); + } + + @Test + @Override + public void testNamedQueryOrderArgs() { + ctx.delegate().testNamedQueryOrderArgs(); + } + + @Test + @Override + public void testQueryOrderArgs() { + ctx.delegate().testQueryOrderArgs(); + } + + @Test + @Override + public void testCreateNamedUpdateStrStrNamedArgs() { + ctx.delegate().testCreateNamedUpdateStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedUpdateStrNamedArgs() { + ctx.delegate().testCreateNamedUpdateStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedUpdateStrOrderArgs() { + ctx.delegate().testCreateNamedUpdateStrOrderArgs(); + } + + @Test + @Override + public void testCreateUpdateNamedArgs() { + ctx.delegate().testCreateUpdateNamedArgs(); + } + + @Test + @Override + public void testCreateUpdateOrderArgs() { + ctx.delegate().testCreateUpdateOrderArgs(); + } + + @Test + @Override + public void testNamedUpdateNamedArgs() { + ctx.delegate().testNamedUpdateNamedArgs(); + } + + @Test + @Override + public void testUpdateOrderArgs() { + ctx.delegate().testUpdateOrderArgs(); + } +} diff --git a/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLSimpleRemoteTestIT.java b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLSimpleRemoteTestIT.java new file mode 100644 index 00000000000..050a0418c28 --- /dev/null +++ b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLSimpleRemoteTestIT.java @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.mysql; + +import io.helidon.tests.integration.dbclient.common.SimpleTest; + +import org.junit.jupiter.api.Test; + +/** + * Remote simple test. + */ +final class MySQLSimpleRemoteTestIT extends MySQLRemoteTest implements SimpleTest { + + MySQLSimpleRemoteTestIT() { + super("/test/simple"); + } + + @Test + @Override + public void testCreateNamedDeleteStrStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDeleteStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDeleteStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDeleteNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithInsertStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithInsertStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithInsertStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDmlWithInsertNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDmlWithInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedDmlWithInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testDmlWithInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithUpdateStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithUpdateStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithUpdateStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDmlWithUpdateNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDmlWithUpdateOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedDmlWithUpdateOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testDmlWithUpdateOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithDeleteStrStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithDeleteStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithDeleteStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDmlWithDeleteNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDmlWithDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedDmlWithDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testDmlWithDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedGetStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedGetStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedGetStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateGetNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateGetOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedGetStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testGetStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedInsertStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedInsertStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedInsertStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateInsertNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryStrStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateQueryNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateQueryOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedQueryOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testQueryOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedUpdateStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedUpdateStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedUpdateStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateUpdateNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateUpdateOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedUpdateNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testUpdateOrderArgs() { + remoteTest(); + } +} diff --git a/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLStatementLocalTestIT.java b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLStatementLocalTestIT.java new file mode 100644 index 00000000000..b277284da2b --- /dev/null +++ b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLStatementLocalTestIT.java @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.mysql; + +import io.helidon.tests.integration.dbclient.common.LocalTextContext; +import io.helidon.tests.integration.dbclient.common.StatementTest; +import io.helidon.tests.integration.dbclient.common.StatementTestImpl; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Local statement test. + */ +final class MySQLStatementLocalTestIT extends MySQLLocalTest implements StatementTest { + + static LocalTextContext ctx; + + @BeforeAll + static void setUp() { + ctx = context(StatementTestImpl::new); + } + + @Test + @Override + public void testCreateNamedQueryNonExistentStmt() { + ctx.delegate().testCreateNamedQueryNonExistentStmt(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithoutArgs() { + ctx.delegate().testCreateNamedQueryNamedAndOrderArgsWithoutArgs(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithArgs() { + ctx.delegate().testCreateNamedQueryNamedAndOrderArgsWithArgs(); + } + + @Test + @Override + public void testCreateNamedQueryNamedArgsSetOrderArg() { + ctx.delegate().testCreateNamedQueryNamedArgsSetOrderArg(); + } + + @Test + @Override + public void testCreateNamedQueryOrderArgsSetNamedArg() { + ctx.delegate().testCreateNamedQueryOrderArgsSetNamedArg(); + } + + @Test + @Override + public void testGetArrayParams() { + ctx.delegate().testGetArrayParams(); + } + + @Test + @Override + public void testGetListParams() { + ctx.delegate().testGetListParams(); + } + + @Test + @Override + public void testGetMapParams() { + ctx.delegate().testGetMapParams(); + } + + @Test + @Override + public void testGetOrderParam() { + ctx.delegate().testGetOrderParam(); + } + + @Test + @Override + public void testGetNamedParam() { + ctx.delegate().testGetNamedParam(); + } + + @Test + @Override + public void testGetMappedNamedParam() { + ctx.delegate().testGetMappedNamedParam(); + } + + @Test + @Override + public void testGetMappedOrderParam() { + ctx.delegate().testGetMappedOrderParam(); + } + + @Test + @Override + public void testQueryArrayParams() { + ctx.delegate().testQueryArrayParams(); + } + + @Test + @Override + public void testQueryListParams() { + ctx.delegate().testQueryListParams(); + } + + @Test + @Override + public void testQueryMapParams() { + ctx.delegate().testQueryMapParams(); + } + + @Test + @Override + public void testQueryMapMissingParams() { + ctx.delegate().testQueryMapMissingParams(); + } + + @Test + @Override + public void testQueryOrderParam() { + ctx.delegate().testQueryOrderParam(); + } + + @Test + @Override + public void testQueryNamedParam() { + ctx.delegate().testQueryNamedParam(); + } + + @Test + @Override + public void testQueryMappedNamedParam() { + ctx.delegate().testQueryMappedNamedParam(); + } + + @Test + @Override + public void testQueryMappedOrderParam() { + ctx.delegate().testQueryMappedOrderParam(); + } + + @Test + @Override + public void testDmlArrayParams() { + ctx.delegate().testDmlArrayParams(); + } + + @Test + @Override + public void testDmlListParams() { + ctx.delegate().testDmlListParams(); + } + + @Test + @Override + public void testDmlMapParams() { + ctx.delegate().testDmlMapParams(); + } + + @Test + @Override + public void testDmlOrderParam() { + ctx.delegate().testDmlOrderParam(); + } + + @Test + @Override + public void testDmlNamedParam() { + ctx.delegate().testDmlNamedParam(); + } + + @Test + @Override + public void testDmlMappedNamedParam() { + ctx.delegate().testDmlMappedNamedParam(); + } + + @Test + @Override + public void testDmlMappedOrderParam() { + ctx.delegate().testDmlMappedOrderParam(); + } +} diff --git a/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLStatementRemoteTestIT.java b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLStatementRemoteTestIT.java new file mode 100644 index 00000000000..d53ee457e42 --- /dev/null +++ b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLStatementRemoteTestIT.java @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.mysql; + +import io.helidon.tests.integration.dbclient.common.StatementTest; + +import org.junit.jupiter.api.Test; + +/** + * Remote statement test. + */ +final class MySQLStatementRemoteTestIT extends MySQLRemoteTest implements StatementTest { + + MySQLStatementRemoteTestIT() { + super("/test/statement"); + } + + @Test + @Override + public void testCreateNamedQueryNonExistentStmt() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithoutArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNamedArgsSetOrderArg() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryOrderArgsSetNamedArg() { + remoteTest(); + } + + @Test + @Override + public void testGetArrayParams() { + remoteTest(); + } + + @Test + @Override + public void testGetListParams() { + remoteTest(); + } + + @Test + @Override + public void testGetMapParams() { + remoteTest(); + } + + @Test + @Override + public void testGetOrderParam() { + remoteTest(); + } + + @Test + @Override + public void testGetNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testGetMappedNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testGetMappedOrderParam() { + remoteTest(); + } + + @Test + @Override + public void testQueryArrayParams() { + remoteTest(); + } + + @Test + @Override + public void testQueryListParams() { + remoteTest(); + } + + @Test + @Override + public void testQueryMapParams() { + remoteTest(); + } + + @Test + @Override + public void testQueryMapMissingParams() { + remoteTest(); + } + + @Test + @Override + public void testQueryOrderParam() { + remoteTest(); + } + + @Test + @Override + public void testQueryNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testQueryMappedNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testQueryMappedOrderParam() { + remoteTest(); + } + + @Test + @Override + public void testDmlArrayParams() { + remoteTest(); + } + + @Test + @Override + public void testDmlListParams() { + remoteTest(); + } + + @Test + @Override + public void testDmlMapParams() { + remoteTest(); + } + + @Test + @Override + public void testDmlOrderParam() { + remoteTest(); + } + + @Test + @Override + public void testDmlNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testDmlMappedNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testDmlMappedOrderParam() { + remoteTest(); + } +} diff --git a/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLTestContainer.java b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLTestContainer.java new file mode 100644 index 00000000000..fdda39063b6 --- /dev/null +++ b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLTestContainer.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.mysql; + +import java.util.Map; +import java.util.function.Supplier; + +import org.testcontainers.containers.MySQLContainer; +import org.testcontainers.utility.DockerImageName; + +/** + * Database container utility. + */ +abstract class MySQLTestContainer { + + private static final DockerImageName IMAGE = DockerImageName.parse("container-registry.oracle.com/mysql/community-server") + .asCompatibleSubstituteFor("mysql"); + + static final MySQLContainer CONTAINER = new MySQLContainer<>(IMAGE) + .withUsername("test") + .withPassword("mysql123") + .withDatabaseName("test"); + + static Map> config() { + return Map.of("db.connection.url", CONTAINER::getJdbcUrl); + } + + private MySQLTestContainer() { + } +} diff --git a/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLTransactionLocalTestIT.java b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLTransactionLocalTestIT.java new file mode 100644 index 00000000000..445ed8d30a3 --- /dev/null +++ b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLTransactionLocalTestIT.java @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.mysql; + +import io.helidon.tests.integration.dbclient.common.LocalTextContext; +import io.helidon.tests.integration.dbclient.common.TransactionTest; +import io.helidon.tests.integration.dbclient.common.TransactionTestImpl; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Local transaction test. + */ +final class MySQLTransactionLocalTestIT extends MySQLLocalTest implements TransactionTest { + + static LocalTextContext ctx; + + @BeforeAll + static void setUp() { + ctx = context(TransactionTestImpl::new); + } + + @Test + @Override + public void testCreateNamedDeleteStrStrOrderArgs() { + ctx.delegate().testCreateNamedDeleteStrStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedDeleteStrNamedArgs() { + ctx.delegate().testCreateNamedDeleteStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDeleteStrOrderArgs() { + ctx.delegate().testCreateNamedDeleteStrOrderArgs(); + } + + @Test + @Override + public void testCreateDeleteNamedArgs() { + ctx.delegate().testCreateDeleteNamedArgs(); + } + + @Test + @Override + public void testCreateDeleteOrderArgs() { + ctx.delegate().testCreateDeleteOrderArgs(); + } + + @Test + @Override + public void testNamedDeleteOrderArgs() { + ctx.delegate().testNamedDeleteOrderArgs(); + } + + @Test + @Override + public void testDeleteOrderArgs() { + ctx.delegate().testDeleteOrderArgs(); + } + + @Test + @Override + public void testCreateNamedQueryNonExistentStmt() { + ctx.delegate().testCreateNamedQueryNonExistentStmt(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithoutArgs() { + ctx.delegate().testCreateNamedQueryNamedAndOrderArgsWithoutArgs(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithArgs() { + ctx.delegate().testCreateNamedQueryNamedAndOrderArgsWithArgs(); + } + + @Test + @Override + public void testCreateNamedQueryNamedArgsSetOrderArg() { + ctx.delegate().testCreateNamedQueryNamedArgsSetOrderArg(); + } + + @Test + @Override + public void testCreateNamedQueryOrderArgsSetNamedArg() { + ctx.delegate().testCreateNamedQueryOrderArgsSetNamedArg(); + } + + @Test + @Override + public void testCreateNamedGetStrStrNamedArgs() { + ctx.delegate().testCreateNamedGetStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedGetStrNamedArgs() { + ctx.delegate().testCreateNamedGetStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedGetStrOrderArgs() { + ctx.delegate().testCreateNamedGetStrOrderArgs(); + } + + @Test + @Override + public void testCreateGetNamedArgs() { + ctx.delegate().testCreateGetNamedArgs(); + } + + @Test + @Override + public void testCreateGetOrderArgs() { + ctx.delegate().testCreateGetOrderArgs(); + } + + @Test + @Override + public void testNamedGetStrOrderArgs() { + ctx.delegate().testNamedGetStrOrderArgs(); + } + + @Test + @Override + public void testGetStrOrderArgs() { + ctx.delegate().testGetStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedInsertStrStrNamedArgs() { + ctx.delegate().testCreateNamedInsertStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedInsertStrNamedArgs() { + ctx.delegate().testCreateNamedInsertStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedInsertStrOrderArgs() { + ctx.delegate().testCreateNamedInsertStrOrderArgs(); + } + + @Test + @Override + public void testCreateInsertNamedArgs() { + ctx.delegate().testCreateInsertNamedArgs(); + } + + @Test + @Override + public void testCreateInsertOrderArgs() { + ctx.delegate().testCreateInsertOrderArgs(); + } + + @Test + @Override + public void testNamedInsertOrderArgs() { + ctx.delegate().testNamedInsertOrderArgs(); + } + + @Test + @Override + public void testInsertOrderArgs() { + ctx.delegate().testInsertOrderArgs(); + } + + @Test + @Override + public void testCreateNamedQueryStrStrOrderArgs() { + ctx.delegate().testCreateNamedQueryStrStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedQueryStrNamedArgs() { + ctx.delegate().testCreateNamedQueryStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedQueryStrOrderArgs() { + ctx.delegate().testCreateNamedQueryStrOrderArgs(); + } + + @Test + @Override + public void testCreateQueryNamedArgs() { + ctx.delegate().testCreateQueryNamedArgs(); + } + + @Test + @Override + public void testCreateQueryOrderArgs() { + ctx.delegate().testCreateQueryOrderArgs(); + } + + @Test + @Override + public void testNamedQueryOrderArgs() { + ctx.delegate().testNamedQueryOrderArgs(); + } + + @Test + @Override + public void testQueryOrderArgs() { + ctx.delegate().testQueryOrderArgs(); + } + + @Test + @Override + public void testCreateNamedUpdateStrStrNamedArgs() { + ctx.delegate().testCreateNamedUpdateStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedUpdateStrNamedArgs() { + ctx.delegate().testCreateNamedUpdateStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedUpdateStrOrderArgs() { + ctx.delegate().testCreateNamedUpdateStrOrderArgs(); + } + + @Test + @Override + public void testCreateUpdateNamedArgs() { + ctx.delegate().testCreateUpdateNamedArgs(); + } + + @Test + @Override + public void testCreateUpdateOrderArgs() { + ctx.delegate().testCreateUpdateOrderArgs(); + } + + @Test + @Override + public void testNamedUpdateNamedArgs() { + ctx.delegate().testNamedUpdateNamedArgs(); + } + + @Test + @Override + public void testUpdateOrderArgs() { + ctx.delegate().testUpdateOrderArgs(); + } +} diff --git a/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLTransactionRemoteTestIT.java b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLTransactionRemoteTestIT.java new file mode 100644 index 00000000000..7e9d495df94 --- /dev/null +++ b/tests/integration/dbclient/mysql/src/test/java/io/helidon/tests/integration/dbclient/mysql/MySQLTransactionRemoteTestIT.java @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.mysql; + +import io.helidon.tests.integration.dbclient.common.TransactionTest; + +import org.junit.jupiter.api.Test; + +/** + * Remote transaction test. + */ +final class MySQLTransactionRemoteTestIT extends MySQLRemoteTest implements TransactionTest { + + MySQLTransactionRemoteTestIT() { + super("/test/transaction"); + } + + @Test + @Override + public void testCreateNamedDeleteStrStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDeleteStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDeleteStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDeleteNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNonExistentStmt() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithoutArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNamedArgsSetOrderArg() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryOrderArgsSetNamedArg() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedGetStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedGetStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedGetStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateGetNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateGetOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedGetStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testGetStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedInsertStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedInsertStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedInsertStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateInsertNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryStrStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateQueryNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateQueryOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedQueryOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testQueryOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedUpdateStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedUpdateStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedUpdateStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateUpdateNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateUpdateOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedUpdateNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testUpdateOrderArgs() { + remoteTest(); + } +} diff --git a/tests/integration/dbclient/oracle/README.md b/tests/integration/dbclient/oracle/README.md new file mode 100644 index 00000000000..b56ff16cc2d --- /dev/null +++ b/tests/integration/dbclient/oracle/README.md @@ -0,0 +1,15 @@ +# DbClient Integration Test Oracle + +To run this test: +```shell +mvn clean verify +``` + +Start the database: +```shell +docker run -d \ + --name oracledb \ + -e ORACLE_PWD=oracle123 \ + -p 1521:1521 \ + container-registry.oracle.com/database/express:latest +``` diff --git a/tests/integration/dbclient/oracle/pom.xml b/tests/integration/dbclient/oracle/pom.xml new file mode 100644 index 00000000000..114e15d4097 --- /dev/null +++ b/tests/integration/dbclient/oracle/pom.xml @@ -0,0 +1,71 @@ + + + + + 4.0.0 + + io.helidon.tests.integration.dbclient + helidon-tests-integration-dbclient-parent + 4.1.0-SNAPSHOT + ../parent/pom.xml + + helidon-tests-integration-dbclient-oracle + Helidon Tests Integration DbClient Oracle + + + + io.helidon.dbclient + helidon-dbclient-jdbc + + + io.helidon.dbclient + helidon-dbclient-metrics-hikari + + + io.helidon.integrations.db + ojdbc + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-libs + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + integration-test + verify + + + + + + + diff --git a/tests/integration/dbclient/oracle/src/main/resources/db.yaml b/tests/integration/dbclient/oracle/src/main/resources/db.yaml new file mode 100644 index 00000000000..f1daebdfa6c --- /dev/null +++ b/tests/integration/dbclient/oracle/src/main/resources/db.yaml @@ -0,0 +1,29 @@ +# +# Copyright (c) 2024 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. +# + +db: + source: jdbc + connection: + url: jdbc:oracle:thin:@localhost:1521/XE + username: system + password: oracle123 + poolName: test + initializationFailTimeout: -1 + connectionTimeout: 2000 + health-check: + statement: "SELECT 1 FROM DUAL" + statements: + ping: "SELECT 1 FROM DUAL" diff --git a/tests/integration/dbclient/oracle/src/main/resources/logging.properties b/tests/integration/dbclient/oracle/src/main/resources/logging.properties new file mode 100644 index 00000000000..d590b197673 --- /dev/null +++ b/tests/integration/dbclient/oracle/src/main/resources/logging.properties @@ -0,0 +1,18 @@ +# +# Copyright (c) 2024 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. +# + +handlers=org.slf4j.bridge.SLF4JBridgeHandler +.level=INFO diff --git a/tests/integration/dbclient/oracle/src/main/resources/simplelogger.properties b/tests/integration/dbclient/oracle/src/main/resources/simplelogger.properties new file mode 100644 index 00000000000..fcc605df165 --- /dev/null +++ b/tests/integration/dbclient/oracle/src/main/resources/simplelogger.properties @@ -0,0 +1,22 @@ +# +# Copyright (c) 2024 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. +# +org.slf4j.simpleLogger.defaultLogLevel=warn +org.slf4j.simpleLogger.showThreadName=false +org.slf4j.simpleLogger.log.org.testcontainers=info +org.slf4j.simpleLogger.log.org.testcontainers.utility=error +org.slf4j.simpleLogger.log.io.helidon=info +org.slf4j.simpleLogger.log.org.hibernate=info +org.slf4j.simpleLogger.log.com.zaxxer=info diff --git a/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleLocalTest.java b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleLocalTest.java new file mode 100644 index 00000000000..eca6525b69e --- /dev/null +++ b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleLocalTest.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.oracle; + +import java.util.function.BiFunction; + +import io.helidon.config.Config; +import io.helidon.dbclient.DbClient; +import io.helidon.tests.integration.dbclient.common.LocalTextContext; + +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +/** + * Base class for the local tests. + */ +@Testcontainers(disabledWithoutDocker = true) +abstract class OracleLocalTest { + + @Container + static final GenericContainer CONTAINER = OracleTestContainer.CONTAINER; + + static LocalTextContext context(BiFunction factory) { + return LocalTextContext.create(factory, OracleTestContainer.config(), true); + } +} diff --git a/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleMiscLocalTestIT.java b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleMiscLocalTestIT.java new file mode 100644 index 00000000000..0f300055622 --- /dev/null +++ b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleMiscLocalTestIT.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.oracle; + +import io.helidon.tests.integration.dbclient.common.LocalTextContext; +import io.helidon.tests.integration.dbclient.common.MiscTest; +import io.helidon.tests.integration.dbclient.common.MiscTestImpl; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Local misc test. + */ +final class OracleMiscLocalTestIT extends OracleLocalTest implements MiscTest { + + static LocalTextContext ctx; + + @BeforeAll + static void setUp() { + ctx = context(MiscTestImpl::new); + } + + @Test + @Override + public void testFlowControl() { + ctx.delegate().testFlowControl(); + } + + @Test + @Override + public void testStatementInterceptor() { + ctx.delegate().testStatementInterceptor(); + } + + @Test + @Override + public void testInsertWithOrderMapping() { + ctx.delegate().testInsertWithOrderMapping(); + } + + @Test + @Override + public void testInsertWithNamedMapping() { + ctx.delegate().testInsertWithNamedMapping(); + } + + @Test + @Override + public void testUpdateWithOrderMapping() { + ctx.delegate().testUpdateWithOrderMapping(); + } + + @Test + @Override + public void testUpdateWithNamedMapping() { + ctx.delegate().testUpdateWithNamedMapping(); + } + + @Test + @Override + public void testDeleteWithOrderMapping() { + ctx.delegate().testDeleteWithOrderMapping(); + } + + @Test + @Override + public void testDeleteWithNamedMapping() { + ctx.delegate().testDeleteWithNamedMapping(); + } + + @Test + @Override + public void testQueryWithMapping() { + ctx.delegate().testQueryWithMapping(); + } + + @Test + @Override + public void testGetWithMapping() { + ctx.delegate().testGetWithMapping(); + } +} diff --git a/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleMiscRemoteTestIT.java b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleMiscRemoteTestIT.java new file mode 100644 index 00000000000..f92984a71ab --- /dev/null +++ b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleMiscRemoteTestIT.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.oracle; + +import io.helidon.tests.integration.dbclient.common.MiscTest; + +import org.junit.jupiter.api.Test; + +/** + * Remote misc test. + */ +final class OracleMiscRemoteTestIT extends OracleRemoteTest implements MiscTest { + + OracleMiscRemoteTestIT() { + super("/test/misc"); + } + + @Test + @Override + public void testFlowControl() { + remoteTest(); + } + + @Test + @Override + public void testStatementInterceptor() { + remoteTest(); + } + + @Test + @Override + public void testInsertWithOrderMapping() { + remoteTest(); + } + + @Test + @Override + public void testInsertWithNamedMapping() { + remoteTest(); + } + + @Test + @Override + public void testUpdateWithOrderMapping() { + remoteTest(); + } + + @Test + @Override + public void testUpdateWithNamedMapping() { + remoteTest(); + } + + @Test + @Override + public void testDeleteWithOrderMapping() { + remoteTest(); + } + + @Test + @Override + public void testDeleteWithNamedMapping() { + remoteTest(); + } + + @Test + @Override + public void testQueryWithMapping() { + remoteTest(); + } + + @Test + @Override + public void testGetWithMapping() { + remoteTest(); + } +} diff --git a/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleObservabilityLocalTestIT.java b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleObservabilityLocalTestIT.java new file mode 100644 index 00000000000..e9288b0895f --- /dev/null +++ b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleObservabilityLocalTestIT.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.oracle; + +import io.helidon.tests.integration.dbclient.common.DbClientITMain; +import io.helidon.tests.integration.dbclient.common.LocalTextContext; +import io.helidon.tests.integration.dbclient.common.ObservabilityTest; +import io.helidon.tests.integration.dbclient.common.ObservabilityTestImpl; +import io.helidon.webclient.http1.Http1Client; +import io.helidon.webserver.WebServerConfig; +import io.helidon.webserver.testing.junit5.ServerTest; +import io.helidon.webserver.testing.junit5.SetUpServer; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Local observability test. + */ +@ServerTest +final class OracleObservabilityLocalTestIT extends OracleLocalTest implements ObservabilityTest { + + private static Http1Client client; + private static LocalTextContext ctx; + + @BeforeAll + static void beforeAll(Http1Client aClient) { + client = aClient; + } + + @SetUpServer + static void setUp(WebServerConfig.Builder builder) { + ctx = context((db, c) -> new ObservabilityTestImpl(db, c, () -> client)); + DbClientITMain.setup(ctx.db(), ctx.config(), builder); + } + + @Test + @Override + public void testHttpHealthNoDetails() { + ctx.delegate().testHttpHealthNoDetails(); + } + + @Test + @Override + public void testHttpHealthDetails() { + ctx.delegate().testHttpHealthDetails(); + } + + @Test + @Override + public void testHttpMetrics() { + ctx.delegate().testHttpMetrics(); + } + + @Test + @Override + public void testHealthCheck() { + ctx.delegate().testHealthCheck(); + } + + @Test + @Override + public void testHealthCheckWithName() { + ctx.delegate().testHealthCheckWithName(); + } + + @Override + @SuppressWarnings("ALL") + public void testHealthCheckWithCustomNamedDML() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testHealthCheckWithCustomDML() { + throw new UnsupportedOperationException(); + } + + @Test + @Override + public void testHealthCheckWithCustomNamedQuery() { + ctx.delegate().testHealthCheckWithCustomNamedQuery(); + } + + @Test + @Override + public void testHealthCheckWithCustomQuery() { + ctx.delegate().testHealthCheckWithCustomQuery(); + } +} diff --git a/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleObservabilityRemoteTestIT.java b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleObservabilityRemoteTestIT.java new file mode 100644 index 00000000000..0332fa332f1 --- /dev/null +++ b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleObservabilityRemoteTestIT.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.oracle; + +import io.helidon.tests.integration.dbclient.common.ObservabilityTest; + +import org.junit.jupiter.api.Test; + +/** + * Remote observability test. + */ +final class OracleObservabilityRemoteTestIT extends OracleRemoteTest implements ObservabilityTest { + + OracleObservabilityRemoteTestIT() { + super("/test/observability"); + } + + @Test + @Override + public void testHttpHealthNoDetails() { + remoteTest(); + } + + @Test + @Override + public void testHttpHealthDetails() { + remoteTest(); + } + + @Test + @Override + public void testHttpMetrics() { + remoteTest(); + } + + @Test + @Override + public void testHealthCheck() { + remoteTest(); + } + + @Test + @Override + public void testHealthCheckWithName() { + remoteTest(); + } + + @Override + @SuppressWarnings("ALL") + public void testHealthCheckWithCustomNamedDML() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testHealthCheckWithCustomDML() { + throw new UnsupportedOperationException(); + } + + @Test + @Override + public void testHealthCheckWithCustomNamedQuery() { + remoteTest(); + } + + @Test + @Override + public void testHealthCheckWithCustomQuery() { + remoteTest(); + } +} diff --git a/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleRemoteTest.java b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleRemoteTest.java new file mode 100644 index 00000000000..8938f039a7e --- /dev/null +++ b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleRemoteTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.oracle; + +import java.nio.file.Path; +import java.util.Map; + +import io.helidon.tests.integration.dbclient.common.RemoteTest; +import io.helidon.tests.integration.harness.ProcessRunner; +import io.helidon.tests.integration.harness.ProcessRunner.ExecMode; +import io.helidon.tests.integration.harness.WaitStrategy; +import io.helidon.tests.integration.harness.TestProcess; +import io.helidon.tests.integration.harness.TestProcesses; + +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +/** + * Base class for the remote tests. + */ +@Testcontainers(disabledWithoutDocker = true) +@TestProcesses +abstract class OracleRemoteTest extends RemoteTest { + + @Container + static final GenericContainer CONTAINER = OracleTestContainer.CONTAINER; + + @TestProcess + static final ProcessRunner PROCESS_RUNNER = ProcessRunner.of(ExecMode.CLASS_PATH) + .finalName("helidon-tests-integration-dbclient-oracle") + .properties(Map.of("java.util.logging.config.file", Path.of("target/classes/logging.properties").toAbsolutePath())) + .properties(OracleTestContainer::config) + .waitingFor(WaitStrategy.waitForPort()); + + /** + * Create a new instance. + * + * @param path base path + */ + @SuppressWarnings("resource") + OracleRemoteTest(String path) { + super(path, PROCESS_RUNNER.process().port()); + } +} diff --git a/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleSimpleLocalTestIT.java b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleSimpleLocalTestIT.java new file mode 100644 index 00000000000..89f1883022a --- /dev/null +++ b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleSimpleLocalTestIT.java @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.oracle; + +import io.helidon.tests.integration.dbclient.common.LocalTextContext; +import io.helidon.tests.integration.dbclient.common.SimpleTest; +import io.helidon.tests.integration.dbclient.common.SimpleTestImpl; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Local simple test. + */ +final class OracleSimpleLocalTestIT extends OracleLocalTest implements SimpleTest { + + static LocalTextContext ctx; + + @BeforeAll + static void setUp() { + ctx = context(SimpleTestImpl::new); + } + + @Test + @Override + public void testCreateNamedDeleteStrStrOrderArgs() { + ctx.delegate().testCreateNamedDeleteStrStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedDeleteStrNamedArgs() { + ctx.delegate().testCreateNamedDeleteStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDeleteStrOrderArgs() { + ctx.delegate().testCreateNamedDeleteStrOrderArgs(); + } + + @Test + @Override + public void testCreateDeleteNamedArgs() { + ctx.delegate().testCreateDeleteNamedArgs(); + } + + @Test + @Override + public void testCreateDeleteOrderArgs() { + ctx.delegate().testCreateDeleteOrderArgs(); + } + + @Test + @Override + public void testNamedDeleteOrderArgs() { + ctx.delegate().testNamedDeleteOrderArgs(); + } + + @Test + @Override + public void testDeleteOrderArgs() { + ctx.delegate().testDeleteOrderArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithInsertStrStrNamedArgs() { + ctx.delegate().testCreateNamedDmlWithInsertStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithInsertStrNamedArgs() { + ctx.delegate().testCreateNamedDmlWithInsertStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithInsertStrOrderArgs() { + ctx.delegate().testCreateNamedDmlWithInsertStrOrderArgs(); + } + + @Test + @Override + public void testCreateDmlWithInsertNamedArgs() { + ctx.delegate().testCreateDmlWithInsertNamedArgs(); + } + + @Test + @Override + public void testCreateDmlWithInsertOrderArgs() { + ctx.delegate().testCreateDmlWithInsertOrderArgs(); + } + + @Test + @Override + public void testNamedDmlWithInsertOrderArgs() { + ctx.delegate().testNamedDmlWithInsertOrderArgs(); + } + + @Test + @Override + public void testDmlWithInsertOrderArgs() { + ctx.delegate().testDmlWithInsertOrderArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithUpdateStrStrNamedArgs() { + ctx.delegate().testCreateNamedDmlWithUpdateStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithUpdateStrNamedArgs() { + ctx.delegate().testCreateNamedDmlWithUpdateStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithUpdateStrOrderArgs() { + ctx.delegate().testCreateNamedDmlWithUpdateStrOrderArgs(); + } + + @Test + @Override + public void testCreateDmlWithUpdateNamedArgs() { + ctx.delegate().testCreateDmlWithUpdateNamedArgs(); + } + + @Test + @Override + public void testCreateDmlWithUpdateOrderArgs() { + ctx.delegate().testCreateDmlWithUpdateOrderArgs(); + } + + @Test + @Override + public void testNamedDmlWithUpdateOrderArgs() { + ctx.delegate().testNamedDmlWithUpdateOrderArgs(); + } + + @Test + @Override + public void testDmlWithUpdateOrderArgs() { + ctx.delegate().testDmlWithUpdateOrderArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithDeleteStrStrOrderArgs() { + ctx.delegate().testCreateNamedDmlWithDeleteStrStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithDeleteStrNamedArgs() { + ctx.delegate().testCreateNamedDmlWithDeleteStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithDeleteStrOrderArgs() { + ctx.delegate().testCreateNamedDmlWithDeleteStrOrderArgs(); + } + + @Test + @Override + public void testCreateDmlWithDeleteNamedArgs() { + ctx.delegate().testCreateDmlWithDeleteNamedArgs(); + } + + @Test + @Override + public void testCreateDmlWithDeleteOrderArgs() { + ctx.delegate().testCreateDmlWithDeleteOrderArgs(); + } + + @Test + @Override + public void testNamedDmlWithDeleteOrderArgs() { + ctx.delegate().testNamedDmlWithDeleteOrderArgs(); + } + + @Test + @Override + public void testDmlWithDeleteOrderArgs() { + ctx.delegate().testDmlWithDeleteOrderArgs(); + } + + @Test + @Override + public void testCreateNamedGetStrStrNamedArgs() { + ctx.delegate().testCreateNamedGetStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedGetStrNamedArgs() { + ctx.delegate().testCreateNamedGetStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedGetStrOrderArgs() { + ctx.delegate().testCreateNamedGetStrOrderArgs(); + } + + @Test + @Override + public void testCreateGetNamedArgs() { + ctx.delegate().testCreateGetNamedArgs(); + } + + @Test + @Override + public void testCreateGetOrderArgs() { + ctx.delegate().testCreateGetOrderArgs(); + } + + @Test + @Override + public void testNamedGetStrOrderArgs() { + ctx.delegate().testNamedGetStrOrderArgs(); + } + + @Test + @Override + public void testGetStrOrderArgs() { + ctx.delegate().testGetStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedInsertStrStrNamedArgs() { + ctx.delegate().testCreateNamedInsertStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedInsertStrNamedArgs() { + ctx.delegate().testCreateNamedInsertStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedInsertStrOrderArgs() { + ctx.delegate().testCreateNamedInsertStrOrderArgs(); + } + + @Test + @Override + public void testCreateInsertNamedArgs() { + ctx.delegate().testCreateInsertNamedArgs(); + } + + @Test + @Override + public void testCreateInsertOrderArgs() { + ctx.delegate().testCreateInsertOrderArgs(); + } + + @Test + @Override + public void testNamedInsertOrderArgs() { + ctx.delegate().testNamedInsertOrderArgs(); + } + + @Test + @Override + public void testInsertOrderArgs() { + ctx.delegate().testInsertOrderArgs(); + } + + @Test + @Override + public void testCreateNamedQueryStrStrOrderArgs() { + ctx.delegate().testCreateNamedQueryStrStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedQueryStrNamedArgs() { + ctx.delegate().testCreateNamedQueryStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedQueryStrOrderArgs() { + ctx.delegate().testCreateNamedQueryStrOrderArgs(); + } + + @Test + @Override + public void testCreateQueryNamedArgs() { + ctx.delegate().testCreateQueryNamedArgs(); + } + + @Test + @Override + public void testCreateQueryOrderArgs() { + ctx.delegate().testCreateQueryOrderArgs(); + } + + @Test + @Override + public void testNamedQueryOrderArgs() { + ctx.delegate().testNamedQueryOrderArgs(); + } + + @Test + @Override + public void testQueryOrderArgs() { + ctx.delegate().testQueryOrderArgs(); + } + + @Test + @Override + public void testCreateNamedUpdateStrStrNamedArgs() { + ctx.delegate().testCreateNamedUpdateStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedUpdateStrNamedArgs() { + ctx.delegate().testCreateNamedUpdateStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedUpdateStrOrderArgs() { + ctx.delegate().testCreateNamedUpdateStrOrderArgs(); + } + + @Test + @Override + public void testCreateUpdateNamedArgs() { + ctx.delegate().testCreateUpdateNamedArgs(); + } + + @Test + @Override + public void testCreateUpdateOrderArgs() { + ctx.delegate().testCreateUpdateOrderArgs(); + } + + @Test + @Override + public void testNamedUpdateNamedArgs() { + ctx.delegate().testNamedUpdateNamedArgs(); + } + + @Test + @Override + public void testUpdateOrderArgs() { + ctx.delegate().testUpdateOrderArgs(); + } +} diff --git a/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleSimpleRemoteTestIT.java b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleSimpleRemoteTestIT.java new file mode 100644 index 00000000000..92db52011dd --- /dev/null +++ b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleSimpleRemoteTestIT.java @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.oracle; + +import io.helidon.tests.integration.dbclient.common.SimpleTest; + +import org.junit.jupiter.api.Test; + +/** + * Remote simple test. + */ +final class OracleSimpleRemoteTestIT extends OracleRemoteTest implements SimpleTest { + + OracleSimpleRemoteTestIT() { + super("/test/simple"); + } + + @Test + @Override + public void testCreateNamedDeleteStrStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDeleteStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDeleteStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDeleteNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithInsertStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithInsertStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithInsertStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDmlWithInsertNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDmlWithInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedDmlWithInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testDmlWithInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithUpdateStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithUpdateStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithUpdateStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDmlWithUpdateNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDmlWithUpdateOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedDmlWithUpdateOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testDmlWithUpdateOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithDeleteStrStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithDeleteStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithDeleteStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDmlWithDeleteNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDmlWithDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedDmlWithDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testDmlWithDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedGetStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedGetStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedGetStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateGetNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateGetOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedGetStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testGetStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedInsertStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedInsertStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedInsertStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateInsertNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryStrStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateQueryNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateQueryOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedQueryOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testQueryOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedUpdateStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedUpdateStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedUpdateStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateUpdateNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateUpdateOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedUpdateNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testUpdateOrderArgs() { + remoteTest(); + } +} diff --git a/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleStatementLocalTestIT.java b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleStatementLocalTestIT.java new file mode 100644 index 00000000000..bdb4564a458 --- /dev/null +++ b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleStatementLocalTestIT.java @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.oracle; + +import io.helidon.tests.integration.dbclient.common.LocalTextContext; +import io.helidon.tests.integration.dbclient.common.StatementTest; +import io.helidon.tests.integration.dbclient.common.StatementTestImpl; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Local statement test. + */ +final class OracleStatementLocalTestIT extends OracleLocalTest implements StatementTest { + + static LocalTextContext ctx; + + @BeforeAll + static void setUp() { + ctx = context(StatementTestImpl::new); + } + + @Test + @Override + public void testCreateNamedQueryNonExistentStmt() { + ctx.delegate().testCreateNamedQueryNonExistentStmt(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithoutArgs() { + ctx.delegate().testCreateNamedQueryNamedAndOrderArgsWithoutArgs(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithArgs() { + ctx.delegate().testCreateNamedQueryNamedAndOrderArgsWithArgs(); + } + + @Test + @Override + public void testCreateNamedQueryNamedArgsSetOrderArg() { + ctx.delegate().testCreateNamedQueryNamedArgsSetOrderArg(); + } + + @Test + @Override + public void testCreateNamedQueryOrderArgsSetNamedArg() { + ctx.delegate().testCreateNamedQueryOrderArgsSetNamedArg(); + } + + @Test + @Override + public void testGetArrayParams() { + ctx.delegate().testGetArrayParams(); + } + + @Test + @Override + public void testGetListParams() { + ctx.delegate().testGetListParams(); + } + + @Test + @Override + public void testGetMapParams() { + ctx.delegate().testGetMapParams(); + } + + @Test + @Override + public void testGetOrderParam() { + ctx.delegate().testGetOrderParam(); + } + + @Test + @Override + public void testGetNamedParam() { + ctx.delegate().testGetNamedParam(); + } + + @Test + @Override + public void testGetMappedNamedParam() { + ctx.delegate().testGetMappedNamedParam(); + } + + @Test + @Override + public void testGetMappedOrderParam() { + ctx.delegate().testGetMappedOrderParam(); + } + + @Test + @Override + public void testQueryArrayParams() { + ctx.delegate().testQueryArrayParams(); + } + + @Test + @Override + public void testQueryListParams() { + ctx.delegate().testQueryListParams(); + } + + @Test + @Override + public void testQueryMapParams() { + ctx.delegate().testQueryMapParams(); + } + + @Test + @Override + public void testQueryMapMissingParams() { + ctx.delegate().testQueryMapMissingParams(); + } + + @Test + @Override + public void testQueryOrderParam() { + ctx.delegate().testQueryOrderParam(); + } + + @Test + @Override + public void testQueryNamedParam() { + ctx.delegate().testQueryNamedParam(); + } + + @Test + @Override + public void testQueryMappedNamedParam() { + ctx.delegate().testQueryMappedNamedParam(); + } + + @Test + @Override + public void testQueryMappedOrderParam() { + ctx.delegate().testQueryMappedOrderParam(); + } + + @Test + @Override + public void testDmlArrayParams() { + ctx.delegate().testDmlArrayParams(); + } + + @Test + @Override + public void testDmlListParams() { + ctx.delegate().testDmlListParams(); + } + + @Test + @Override + public void testDmlMapParams() { + ctx.delegate().testDmlMapParams(); + } + + @Test + @Override + public void testDmlOrderParam() { + ctx.delegate().testDmlOrderParam(); + } + + @Test + @Override + public void testDmlNamedParam() { + ctx.delegate().testDmlNamedParam(); + } + + @Test + @Override + public void testDmlMappedNamedParam() { + ctx.delegate().testDmlMappedNamedParam(); + } + + @Test + @Override + public void testDmlMappedOrderParam() { + ctx.delegate().testDmlMappedOrderParam(); + } +} diff --git a/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleStatementRemoteTestIT.java b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleStatementRemoteTestIT.java new file mode 100644 index 00000000000..87583f9dc73 --- /dev/null +++ b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleStatementRemoteTestIT.java @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.oracle; + +import io.helidon.tests.integration.dbclient.common.StatementTest; + +import org.junit.jupiter.api.Test; + +/** + * Remote statement test. + */ +final class OracleStatementRemoteTestIT extends OracleRemoteTest implements StatementTest { + + OracleStatementRemoteTestIT() { + super("/test/statement"); + } + + @Test + @Override + public void testCreateNamedQueryNonExistentStmt() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithoutArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNamedArgsSetOrderArg() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryOrderArgsSetNamedArg() { + remoteTest(); + } + + @Test + @Override + public void testGetArrayParams() { + remoteTest(); + } + + @Test + @Override + public void testGetListParams() { + remoteTest(); + } + + @Test + @Override + public void testGetMapParams() { + remoteTest(); + } + + @Test + @Override + public void testGetOrderParam() { + remoteTest(); + } + + @Test + @Override + public void testGetNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testGetMappedNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testGetMappedOrderParam() { + remoteTest(); + } + + @Test + @Override + public void testQueryArrayParams() { + remoteTest(); + } + + @Test + @Override + public void testQueryListParams() { + remoteTest(); + } + + @Test + @Override + public void testQueryMapParams() { + remoteTest(); + } + + @Test + @Override + public void testQueryMapMissingParams() { + remoteTest(); + } + + @Test + @Override + public void testQueryOrderParam() { + remoteTest(); + } + + @Test + @Override + public void testQueryNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testQueryMappedNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testQueryMappedOrderParam() { + remoteTest(); + } + + @Test + @Override + public void testDmlArrayParams() { + remoteTest(); + } + + @Test + @Override + public void testDmlListParams() { + remoteTest(); + } + + @Test + @Override + public void testDmlMapParams() { + remoteTest(); + } + + @Test + @Override + public void testDmlOrderParam() { + remoteTest(); + } + + @Test + @Override + public void testDmlNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testDmlMappedNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testDmlMappedOrderParam() { + remoteTest(); + } +} diff --git a/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleTestContainer.java b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleTestContainer.java new file mode 100644 index 00000000000..1fc744dc48f --- /dev/null +++ b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleTestContainer.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.oracle; + +import java.time.Duration; +import java.util.Map; +import java.util.function.Supplier; + +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.utility.DockerImageName; + +/** + * Database container utility. + */ +abstract class OracleTestContainer { + + private static final DockerImageName IMAGE = DockerImageName.parse("container-registry.oracle.com/database/express"); + + static final GenericContainer CONTAINER = new GenericContainer<>(IMAGE) + .withEnv("ORACLE_PWD", "oracle123") + .withExposedPorts(1521) + .waitingFor(Wait.forHealthcheck() + .withStartupTimeout(Duration.ofMinutes(5))); + + static Map> config() { + return Map.of("db.connection.url", OracleTestContainer::jdbcUrl); + } + + private static String jdbcUrl() { + return "jdbc:oracle:thin:@localhost:%s/XE".formatted(CONTAINER.getMappedPort(1521)); + } + + private OracleTestContainer() { + } +} diff --git a/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleTransactionLocalTestIT.java b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleTransactionLocalTestIT.java new file mode 100644 index 00000000000..53a7a668521 --- /dev/null +++ b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleTransactionLocalTestIT.java @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.oracle; + +import io.helidon.tests.integration.dbclient.common.LocalTextContext; +import io.helidon.tests.integration.dbclient.common.TransactionTest; +import io.helidon.tests.integration.dbclient.common.TransactionTestImpl; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Local transaction test. + */ +final class OracleTransactionLocalTestIT extends OracleLocalTest implements TransactionTest { + + static LocalTextContext ctx; + + @BeforeAll + static void setUp() { + ctx = context(TransactionTestImpl::new); + } + + @Test + @Override + public void testCreateNamedDeleteStrStrOrderArgs() { + ctx.delegate().testCreateNamedDeleteStrStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedDeleteStrNamedArgs() { + ctx.delegate().testCreateNamedDeleteStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDeleteStrOrderArgs() { + ctx.delegate().testCreateNamedDeleteStrOrderArgs(); + } + + @Test + @Override + public void testCreateDeleteNamedArgs() { + ctx.delegate().testCreateDeleteNamedArgs(); + } + + @Test + @Override + public void testCreateDeleteOrderArgs() { + ctx.delegate().testCreateDeleteOrderArgs(); + } + + @Test + @Override + public void testNamedDeleteOrderArgs() { + ctx.delegate().testNamedDeleteOrderArgs(); + } + + @Test + @Override + public void testDeleteOrderArgs() { + ctx.delegate().testDeleteOrderArgs(); + } + + @Test + @Override + public void testCreateNamedQueryNonExistentStmt() { + ctx.delegate().testCreateNamedQueryNonExistentStmt(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithoutArgs() { + ctx.delegate().testCreateNamedQueryNamedAndOrderArgsWithoutArgs(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithArgs() { + ctx.delegate().testCreateNamedQueryNamedAndOrderArgsWithArgs(); + } + + @Test + @Override + public void testCreateNamedQueryNamedArgsSetOrderArg() { + ctx.delegate().testCreateNamedQueryNamedArgsSetOrderArg(); + } + + @Test + @Override + public void testCreateNamedQueryOrderArgsSetNamedArg() { + ctx.delegate().testCreateNamedQueryOrderArgsSetNamedArg(); + } + + @Test + @Override + public void testCreateNamedGetStrStrNamedArgs() { + ctx.delegate().testCreateNamedGetStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedGetStrNamedArgs() { + ctx.delegate().testCreateNamedGetStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedGetStrOrderArgs() { + ctx.delegate().testCreateNamedGetStrOrderArgs(); + } + + @Test + @Override + public void testCreateGetNamedArgs() { + ctx.delegate().testCreateGetNamedArgs(); + } + + @Test + @Override + public void testCreateGetOrderArgs() { + ctx.delegate().testCreateGetOrderArgs(); + } + + @Test + @Override + public void testNamedGetStrOrderArgs() { + ctx.delegate().testNamedGetStrOrderArgs(); + } + + @Test + @Override + public void testGetStrOrderArgs() { + ctx.delegate().testGetStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedInsertStrStrNamedArgs() { + ctx.delegate().testCreateNamedInsertStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedInsertStrNamedArgs() { + ctx.delegate().testCreateNamedInsertStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedInsertStrOrderArgs() { + ctx.delegate().testCreateNamedInsertStrOrderArgs(); + } + + @Test + @Override + public void testCreateInsertNamedArgs() { + ctx.delegate().testCreateInsertNamedArgs(); + } + + @Test + @Override + public void testCreateInsertOrderArgs() { + ctx.delegate().testCreateInsertOrderArgs(); + } + + @Test + @Override + public void testNamedInsertOrderArgs() { + ctx.delegate().testNamedInsertOrderArgs(); + } + + @Test + @Override + public void testInsertOrderArgs() { + ctx.delegate().testInsertOrderArgs(); + } + + @Test + @Override + public void testCreateNamedQueryStrStrOrderArgs() { + ctx.delegate().testCreateNamedQueryStrStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedQueryStrNamedArgs() { + ctx.delegate().testCreateNamedQueryStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedQueryStrOrderArgs() { + ctx.delegate().testCreateNamedQueryStrOrderArgs(); + } + + @Test + @Override + public void testCreateQueryNamedArgs() { + ctx.delegate().testCreateQueryNamedArgs(); + } + + @Test + @Override + public void testCreateQueryOrderArgs() { + ctx.delegate().testCreateQueryOrderArgs(); + } + + @Test + @Override + public void testNamedQueryOrderArgs() { + ctx.delegate().testNamedQueryOrderArgs(); + } + + @Test + @Override + public void testQueryOrderArgs() { + ctx.delegate().testQueryOrderArgs(); + } + + @Test + @Override + public void testCreateNamedUpdateStrStrNamedArgs() { + ctx.delegate().testCreateNamedUpdateStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedUpdateStrNamedArgs() { + ctx.delegate().testCreateNamedUpdateStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedUpdateStrOrderArgs() { + ctx.delegate().testCreateNamedUpdateStrOrderArgs(); + } + + @Test + @Override + public void testCreateUpdateNamedArgs() { + ctx.delegate().testCreateUpdateNamedArgs(); + } + + @Test + @Override + public void testCreateUpdateOrderArgs() { + ctx.delegate().testCreateUpdateOrderArgs(); + } + + @Test + @Override + public void testNamedUpdateNamedArgs() { + ctx.delegate().testNamedUpdateNamedArgs(); + } + + @Test + @Override + public void testUpdateOrderArgs() { + ctx.delegate().testUpdateOrderArgs(); + } +} diff --git a/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleTransactionRemoteTestIT.java b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleTransactionRemoteTestIT.java new file mode 100644 index 00000000000..c23b5caf5ff --- /dev/null +++ b/tests/integration/dbclient/oracle/src/test/java/io/helidon/tests/integration/dbclient/oracle/OracleTransactionRemoteTestIT.java @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.oracle; + +import io.helidon.tests.integration.dbclient.common.TransactionTest; + +import org.junit.jupiter.api.Test; + +/** + * Remote transaction test. + */ +final class OracleTransactionRemoteTestIT extends OracleRemoteTest implements TransactionTest { + + OracleTransactionRemoteTestIT() { + super("/test/transaction"); + } + + @Test + @Override + public void testCreateNamedDeleteStrStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDeleteStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDeleteStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDeleteNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNonExistentStmt() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithoutArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNamedArgsSetOrderArg() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryOrderArgsSetNamedArg() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedGetStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedGetStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedGetStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateGetNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateGetOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedGetStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testGetStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedInsertStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedInsertStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedInsertStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateInsertNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryStrStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateQueryNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateQueryOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedQueryOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testQueryOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedUpdateStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedUpdateStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedUpdateStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateUpdateNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateUpdateOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedUpdateNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testUpdateOrderArgs() { + remoteTest(); + } +} diff --git a/tests/integration/dbclient/parent/pom.xml b/tests/integration/dbclient/parent/pom.xml new file mode 100644 index 00000000000..2acb24b05ed --- /dev/null +++ b/tests/integration/dbclient/parent/pom.xml @@ -0,0 +1,151 @@ + + + + + 4.0.0 + + io.helidon.applications + helidon-se + 4.1.0-SNAPSHOT + ../../../../applications/se/pom.xml + + io.helidon.tests.integration.dbclient + helidon-tests-integration-dbclient-parent + Helidon Tests Integration DbClient Parent + pom + + + io.helidon.tests.integration.dbclient.common.DbClientITMain + true + + + + + io.helidon.dbclient + helidon-dbclient-metrics + + + io.helidon.tests.integration.dbclient + helidon-tests-integration-dbclient-common + ${project.version} + + + io.helidon.logging + helidon-logging-slf4j + + + org.slf4j + jul-to-slf4j + + + org.slf4j + slf4j-simple + + + org.junit.jupiter + junit-jupiter-api + test + + + + org.testcontainers + junit-jupiter + test + + + io.helidon.tests.integration + helidon-tests-integration-harness + ${project.version} + test + + + io.helidon.webserver.testing.junit5 + helidon-webserver-testing-junit5 + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + **/*IT + + + + ${project.build.outputDirectory}/logging.properties + + + ${redirectTestOutputToFile} + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + ${project.build.testOutputDirectory}/logging.properties + + + ${redirectTestOutputToFile} + ${project.build.outputDirectory} + + + + + + + + remote + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + **/*RemoteTestIT + + + + + + + + local + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + **/*LocalTestIT + + + + + + + + diff --git a/tests/integration/dbclient/pgsql/README.md b/tests/integration/dbclient/pgsql/README.md new file mode 100644 index 00000000000..73896ea8974 --- /dev/null +++ b/tests/integration/dbclient/pgsql/README.md @@ -0,0 +1,22 @@ +# DbClient Integration Test PostgreSQL + +To run this test: +```shell +mvn clean verify +``` + +Build the Docker image: +```shell +docker build etc/docker -t pgsql +``` + +Start the database: +```shell +docker run -d \ + --name pgsql \ + -e POSTGRES_USER=test \ + -e POSTGRES_PASSWORD=pgsql123 \ + -e POSTGRES_DB=test \ + -p 5432:5432 \ + pgsql +``` diff --git a/tests/integration/dbclient/pgsql/etc/docker/Dockerfile b/tests/integration/dbclient/pgsql/etc/docker/Dockerfile new file mode 100644 index 00000000000..f0778bb6852 --- /dev/null +++ b/tests/integration/dbclient/pgsql/etc/docker/Dockerfile @@ -0,0 +1,27 @@ +# +# Copyright (c) 2024 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. +# + +FROM oraclelinux:9-slim + +RUN microdnf install postgresql-server && microdnf clean all +ADD entrypoint.sh /usr/local/bin/ + +ENV PGDATA /var/lib/pgsql/data +USER postgres +ENTRYPOINT ["entrypoint.sh"] +STOPSIGNAL SIGINT +EXPOSE 5432 +CMD ["postgres"] diff --git a/tests/integration/dbclient/pgsql/etc/docker/entrypoint.sh b/tests/integration/dbclient/pgsql/etc/docker/entrypoint.sh new file mode 100755 index 00000000000..701e1e3a4e1 --- /dev/null +++ b/tests/integration/dbclient/pgsql/etc/docker/entrypoint.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2024 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. +# +set -Eeo pipefail + +PGDATA="${PGDATA:-/var/lib/pgsql/data}" + +# initialize the data directory +initdb \ + --username="${POSTGRES_USER:-test}" \ + --pwfile=<(printf "%s" "${POSTGRES_PASSWORD:-test}") \ + -D "${PGDATA}" + +# update config file +# - listen on all network interfaces +# - turn off logging collector to log to the console +sed -e "s/^#listen_addresses = 'localhost'/listen_addresses = '*'/g" \ + -e "s/logging_collector = on/logging_collector = off/g" \ + -e "s/^#session_replication_role = 'origin'/session_replication_role = '${POSTGRES_SRR:-origin}'/g" \ + -i "${PGDATA}/postgresql.conf" + +# enabling trust for all connections +printf 'host all all all %s\n' "$(postgres -C password_encryption)" >> "${PGDATA}/pg_hba.conf" + +# temporary start to create the database +pg_ctl -D "${PGDATA}" -w start +psql \ + --username "${POSTGRES_USER:-test}" \ + --no-password \ + --dbname postgres \ + --set db="${POSTGRES_DB:-test}" <<-'EOSQL' + create database :"db"; + set session_replication_role = replica; +EOSQL +pg_ctl -D "${PGDATA}" -m fast -w stop + +exec "${@}" diff --git a/tests/integration/dbclient/pgsql/pom.xml b/tests/integration/dbclient/pgsql/pom.xml new file mode 100644 index 00000000000..63f11281e70 --- /dev/null +++ b/tests/integration/dbclient/pgsql/pom.xml @@ -0,0 +1,80 @@ + + + + + 4.0.0 + + io.helidon.tests.integration.dbclient + helidon-tests-integration-dbclient-parent + 4.1.0-SNAPSHOT + ../parent/pom.xml + + helidon-tests-integration-dbclient-pgsql + Helidon Tests Integration DbClient PostGreSQL + + + + io.helidon.dbclient + helidon-dbclient-jdbc + + + io.helidon.dbclient + helidon-dbclient-metrics-hikari + + + io.helidon.integrations.db + helidon-integrations-db-pgsql + + + org.postgresql + postgresql + + + org.testcontainers + jdbc + test + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-libs + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + integration-test + verify + + + + + + + diff --git a/tests/integration/dbclient/pgsql/src/main/resources/db.yaml b/tests/integration/dbclient/pgsql/src/main/resources/db.yaml new file mode 100644 index 00000000000..25d524ca4d8 --- /dev/null +++ b/tests/integration/dbclient/pgsql/src/main/resources/db.yaml @@ -0,0 +1,28 @@ +# +# Copyright (c) 2024 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. +# + +db: + source: jdbc + connection: + url: jdbc:postgresql://localhost:5432/test + username: test + password: pgsql123 + poolName: test + initializationFailTimeout: -1 + connectionTimeout: 2000 + health-check: + type: query + statement: "SELECT 0" diff --git a/tests/integration/dbclient/pgsql/src/main/resources/logging.properties b/tests/integration/dbclient/pgsql/src/main/resources/logging.properties new file mode 100644 index 00000000000..d590b197673 --- /dev/null +++ b/tests/integration/dbclient/pgsql/src/main/resources/logging.properties @@ -0,0 +1,18 @@ +# +# Copyright (c) 2024 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. +# + +handlers=org.slf4j.bridge.SLF4JBridgeHandler +.level=INFO diff --git a/tests/integration/dbclient/pgsql/src/main/resources/simplelogger.properties b/tests/integration/dbclient/pgsql/src/main/resources/simplelogger.properties new file mode 100644 index 00000000000..fcc605df165 --- /dev/null +++ b/tests/integration/dbclient/pgsql/src/main/resources/simplelogger.properties @@ -0,0 +1,22 @@ +# +# Copyright (c) 2024 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. +# +org.slf4j.simpleLogger.defaultLogLevel=warn +org.slf4j.simpleLogger.showThreadName=false +org.slf4j.simpleLogger.log.org.testcontainers=info +org.slf4j.simpleLogger.log.org.testcontainers.utility=error +org.slf4j.simpleLogger.log.io.helidon=info +org.slf4j.simpleLogger.log.org.hibernate=info +org.slf4j.simpleLogger.log.com.zaxxer=info diff --git a/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLLocalTest.java b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLLocalTest.java new file mode 100644 index 00000000000..501182d2f9b --- /dev/null +++ b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLLocalTest.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.pgsql; + +import java.util.function.BiFunction; + +import io.helidon.config.Config; +import io.helidon.dbclient.DbClient; +import io.helidon.tests.integration.dbclient.common.LocalTextContext; + +import org.testcontainers.containers.JdbcDatabaseContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +/** + * Base class for the local tests. + */ +@Testcontainers(disabledWithoutDocker = true) +abstract class PostgreSQLLocalTest { + + @Container + static final JdbcDatabaseContainer CONTAINER = PostgreSQLTestContainer.CONTAINER; + + static LocalTextContext context(BiFunction factory) { + return LocalTextContext.create(factory, PostgreSQLTestContainer.config(), true); + } +} diff --git a/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLMiscLocalTestIT.java b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLMiscLocalTestIT.java new file mode 100644 index 00000000000..8a36c02b69c --- /dev/null +++ b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLMiscLocalTestIT.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.pgsql; + +import io.helidon.tests.integration.dbclient.common.LocalTextContext; +import io.helidon.tests.integration.dbclient.common.MiscTest; +import io.helidon.tests.integration.dbclient.common.MiscTestImpl; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Local misc test. + */ +final class PostgreSQLMiscLocalTestIT extends PostgreSQLLocalTest implements MiscTest { + + static LocalTextContext ctx; + + @BeforeAll + static void setUp() { + ctx = context(MiscTestImpl::new); + } + + @Test + @Override + public void testFlowControl() { + ctx.delegate().testFlowControl(); + } + + @Test + @Override + public void testStatementInterceptor() { + ctx.delegate().testStatementInterceptor(); + } + + @Test + @Override + public void testInsertWithOrderMapping() { + ctx.delegate().testInsertWithOrderMapping(); + } + + @Test + @Override + public void testInsertWithNamedMapping() { + ctx.delegate().testInsertWithNamedMapping(); + } + + @Test + @Override + public void testUpdateWithOrderMapping() { + ctx.delegate().testUpdateWithOrderMapping(); + } + + @Test + @Override + public void testUpdateWithNamedMapping() { + ctx.delegate().testUpdateWithNamedMapping(); + } + + @Test + @Override + public void testDeleteWithOrderMapping() { + ctx.delegate().testDeleteWithOrderMapping(); + } + + @Test + @Override + public void testDeleteWithNamedMapping() { + ctx.delegate().testDeleteWithNamedMapping(); + } + + @Test + @Override + public void testQueryWithMapping() { + ctx.delegate().testQueryWithMapping(); + } + + @Test + @Override + public void testGetWithMapping() { + ctx.delegate().testGetWithMapping(); + } +} diff --git a/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLMiscRemoteTestIT.java b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLMiscRemoteTestIT.java new file mode 100644 index 00000000000..3dacb53dbd2 --- /dev/null +++ b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLMiscRemoteTestIT.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.pgsql; + +import io.helidon.tests.integration.dbclient.common.MiscTest; + +import org.junit.jupiter.api.Test; + +/** + * Remote misc test. + */ +final class PostgreSQLMiscRemoteTestIT extends PostgreSQLRemoteTest implements MiscTest { + + PostgreSQLMiscRemoteTestIT() { + super("/test/misc"); + } + + @Test + @Override + public void testFlowControl() { + remoteTest(); + } + + @Test + @Override + public void testStatementInterceptor() { + remoteTest(); + } + + @Test + @Override + public void testInsertWithOrderMapping() { + remoteTest(); + } + + @Test + @Override + public void testInsertWithNamedMapping() { + remoteTest(); + } + + @Test + @Override + public void testUpdateWithOrderMapping() { + remoteTest(); + } + + @Test + @Override + public void testUpdateWithNamedMapping() { + remoteTest(); + } + + @Test + @Override + public void testDeleteWithOrderMapping() { + remoteTest(); + } + + @Test + @Override + public void testDeleteWithNamedMapping() { + remoteTest(); + } + + @Test + @Override + public void testQueryWithMapping() { + remoteTest(); + } + + @Test + @Override + public void testGetWithMapping() { + remoteTest(); + } +} diff --git a/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLObservabilityLocalTestIT.java b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLObservabilityLocalTestIT.java new file mode 100644 index 00000000000..7bd68bf171b --- /dev/null +++ b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLObservabilityLocalTestIT.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.pgsql; + +import io.helidon.tests.integration.dbclient.common.DbClientITMain; +import io.helidon.tests.integration.dbclient.common.LocalTextContext; +import io.helidon.tests.integration.dbclient.common.ObservabilityTest; +import io.helidon.tests.integration.dbclient.common.ObservabilityTestImpl; +import io.helidon.webclient.http1.Http1Client; +import io.helidon.webserver.WebServerConfig; +import io.helidon.webserver.testing.junit5.ServerTest; +import io.helidon.webserver.testing.junit5.SetUpServer; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Local observability test. + */ +@ServerTest +final class PostgreSQLObservabilityLocalTestIT extends PostgreSQLLocalTest implements ObservabilityTest { + + private static Http1Client client; + private static LocalTextContext ctx; + + @BeforeAll + static void beforeAll(Http1Client aClient) { + client = aClient; + } + + @SetUpServer + static void setUp(WebServerConfig.Builder builder) { + ctx = context((db, c) -> new ObservabilityTestImpl(db, c, () -> client)); + DbClientITMain.setup(ctx.db(), ctx.config(), builder); + } + + @Test + @Override + public void testHttpHealthNoDetails() { + ctx.delegate().testHttpHealthNoDetails(); + } + + @Test + @Override + public void testHttpHealthDetails() { + ctx.delegate().testHttpHealthDetails(); + } + + @Test + @Override + public void testHttpMetrics() { + ctx.delegate().testHttpMetrics(); + } + + @Test + @Override + public void testHealthCheck() { + ctx.delegate().testHealthCheck(); + } + + @Test + @Override + public void testHealthCheckWithName() { + ctx.delegate().testHealthCheckWithName(); + } + + @Override + @SuppressWarnings("ALL") + public void testHealthCheckWithCustomNamedDML() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testHealthCheckWithCustomDML() { + throw new UnsupportedOperationException(); + } + + @Test + @Override + public void testHealthCheckWithCustomNamedQuery() { + ctx.delegate().testHealthCheckWithCustomNamedQuery(); + } + + @Test + @Override + public void testHealthCheckWithCustomQuery() { + ctx.delegate().testHealthCheckWithCustomQuery(); + } +} diff --git a/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLObservabilityRemoteTestIT.java b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLObservabilityRemoteTestIT.java new file mode 100644 index 00000000000..3a9a8fddf3b --- /dev/null +++ b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLObservabilityRemoteTestIT.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.pgsql; + +import io.helidon.tests.integration.dbclient.common.ObservabilityTest; + +import org.junit.jupiter.api.Test; + +/** + * Remote observability test. + */ +final class PostgreSQLObservabilityRemoteTestIT extends PostgreSQLRemoteTest implements ObservabilityTest { + + PostgreSQLObservabilityRemoteTestIT() { + super("/test/observability"); + } + + @Test + @Override + public void testHttpHealthNoDetails() { + remoteTest(); + } + + @Test + @Override + public void testHttpHealthDetails() { + remoteTest(); + } + + @Test + @Override + public void testHttpMetrics() { + remoteTest(); + } + + @Test + @Override + public void testHealthCheck() { + remoteTest(); + } + + @Test + @Override + public void testHealthCheckWithName() { + remoteTest(); + } + + @Override + @SuppressWarnings("ALL") + public void testHealthCheckWithCustomNamedDML() { + throw new UnsupportedOperationException(); + } + + @Override + @SuppressWarnings("ALL") + public void testHealthCheckWithCustomDML() { + throw new UnsupportedOperationException(); + } + + @Test + @Override + public void testHealthCheckWithCustomNamedQuery() { + remoteTest(); + } + + @Test + @Override + public void testHealthCheckWithCustomQuery() { + remoteTest(); + } +} diff --git a/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLRemoteTest.java b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLRemoteTest.java new file mode 100644 index 00000000000..1f6bb5fc038 --- /dev/null +++ b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLRemoteTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.pgsql; + +import java.nio.file.Path; +import java.util.Map; + +import io.helidon.tests.integration.dbclient.common.RemoteTest; +import io.helidon.tests.integration.harness.ProcessRunner; +import io.helidon.tests.integration.harness.ProcessRunner.ExecMode; +import io.helidon.tests.integration.harness.WaitStrategy; +import io.helidon.tests.integration.harness.TestProcess; +import io.helidon.tests.integration.harness.TestProcesses; + +import org.testcontainers.containers.JdbcDatabaseContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +/** + * Base class for the remote tests. + */ +@Testcontainers(disabledWithoutDocker = true) +@TestProcesses +abstract class PostgreSQLRemoteTest extends RemoteTest { + + @Container + static final JdbcDatabaseContainer CONTAINER = PostgreSQLTestContainer.CONTAINER; + + @TestProcess + static final ProcessRunner PROCESS_RUNNER = ProcessRunner.of(ExecMode.CLASS_PATH) + .finalName("helidon-tests-integration-dbclient-pgsql") + .properties(Map.of("java.util.logging.config.file", Path.of("target/classes/logging.properties").toAbsolutePath())) + .properties(PostgreSQLTestContainer::config) + .waitingFor(WaitStrategy.waitForPort()); + + /** + * Create a new instance. + * + * @param path base path + */ + @SuppressWarnings("resource") + PostgreSQLRemoteTest(String path) { + super(path, PROCESS_RUNNER.process().port()); + } +} diff --git a/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLSimpleLocalTestIT.java b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLSimpleLocalTestIT.java new file mode 100644 index 00000000000..a8fdbfd5380 --- /dev/null +++ b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLSimpleLocalTestIT.java @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.pgsql; + +import io.helidon.tests.integration.dbclient.common.LocalTextContext; +import io.helidon.tests.integration.dbclient.common.SimpleTest; +import io.helidon.tests.integration.dbclient.common.SimpleTestImpl; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Local simple test. + */ +final class PostgreSQLSimpleLocalTestIT extends PostgreSQLLocalTest implements SimpleTest { + + static LocalTextContext ctx; + + @BeforeAll + static void setUp() { + ctx = context(SimpleTestImpl::new); + } + + @Test + @Override + public void testCreateNamedDeleteStrStrOrderArgs() { + ctx.delegate().testCreateNamedDeleteStrStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedDeleteStrNamedArgs() { + ctx.delegate().testCreateNamedDeleteStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDeleteStrOrderArgs() { + ctx.delegate().testCreateNamedDeleteStrOrderArgs(); + } + + @Test + @Override + public void testCreateDeleteNamedArgs() { + ctx.delegate().testCreateDeleteNamedArgs(); + } + + @Test + @Override + public void testCreateDeleteOrderArgs() { + ctx.delegate().testCreateDeleteOrderArgs(); + } + + @Test + @Override + public void testNamedDeleteOrderArgs() { + ctx.delegate().testNamedDeleteOrderArgs(); + } + + @Test + @Override + public void testDeleteOrderArgs() { + ctx.delegate().testDeleteOrderArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithInsertStrStrNamedArgs() { + ctx.delegate().testCreateNamedDmlWithInsertStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithInsertStrNamedArgs() { + ctx.delegate().testCreateNamedDmlWithInsertStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithInsertStrOrderArgs() { + ctx.delegate().testCreateNamedDmlWithInsertStrOrderArgs(); + } + + @Test + @Override + public void testCreateDmlWithInsertNamedArgs() { + ctx.delegate().testCreateDmlWithInsertNamedArgs(); + } + + @Test + @Override + public void testCreateDmlWithInsertOrderArgs() { + ctx.delegate().testCreateDmlWithInsertOrderArgs(); + } + + @Test + @Override + public void testNamedDmlWithInsertOrderArgs() { + ctx.delegate().testNamedDmlWithInsertOrderArgs(); + } + + @Test + @Override + public void testDmlWithInsertOrderArgs() { + ctx.delegate().testDmlWithInsertOrderArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithUpdateStrStrNamedArgs() { + ctx.delegate().testCreateNamedDmlWithUpdateStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithUpdateStrNamedArgs() { + ctx.delegate().testCreateNamedDmlWithUpdateStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithUpdateStrOrderArgs() { + ctx.delegate().testCreateNamedDmlWithUpdateStrOrderArgs(); + } + + @Test + @Override + public void testCreateDmlWithUpdateNamedArgs() { + ctx.delegate().testCreateDmlWithUpdateNamedArgs(); + } + + @Test + @Override + public void testCreateDmlWithUpdateOrderArgs() { + ctx.delegate().testCreateDmlWithUpdateOrderArgs(); + } + + @Test + @Override + public void testNamedDmlWithUpdateOrderArgs() { + ctx.delegate().testNamedDmlWithUpdateOrderArgs(); + } + + @Test + @Override + public void testDmlWithUpdateOrderArgs() { + ctx.delegate().testDmlWithUpdateOrderArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithDeleteStrStrOrderArgs() { + ctx.delegate().testCreateNamedDmlWithDeleteStrStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithDeleteStrNamedArgs() { + ctx.delegate().testCreateNamedDmlWithDeleteStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDmlWithDeleteStrOrderArgs() { + ctx.delegate().testCreateNamedDmlWithDeleteStrOrderArgs(); + } + + @Test + @Override + public void testCreateDmlWithDeleteNamedArgs() { + ctx.delegate().testCreateDmlWithDeleteNamedArgs(); + } + + @Test + @Override + public void testCreateDmlWithDeleteOrderArgs() { + ctx.delegate().testCreateDmlWithDeleteOrderArgs(); + } + + @Test + @Override + public void testNamedDmlWithDeleteOrderArgs() { + ctx.delegate().testNamedDmlWithDeleteOrderArgs(); + } + + @Test + @Override + public void testDmlWithDeleteOrderArgs() { + ctx.delegate().testDmlWithDeleteOrderArgs(); + } + + @Test + @Override + public void testCreateNamedGetStrStrNamedArgs() { + ctx.delegate().testCreateNamedGetStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedGetStrNamedArgs() { + ctx.delegate().testCreateNamedGetStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedGetStrOrderArgs() { + ctx.delegate().testCreateNamedGetStrOrderArgs(); + } + + @Test + @Override + public void testCreateGetNamedArgs() { + ctx.delegate().testCreateGetNamedArgs(); + } + + @Test + @Override + public void testCreateGetOrderArgs() { + ctx.delegate().testCreateGetOrderArgs(); + } + + @Test + @Override + public void testNamedGetStrOrderArgs() { + ctx.delegate().testNamedGetStrOrderArgs(); + } + + @Test + @Override + public void testGetStrOrderArgs() { + ctx.delegate().testGetStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedInsertStrStrNamedArgs() { + ctx.delegate().testCreateNamedInsertStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedInsertStrNamedArgs() { + ctx.delegate().testCreateNamedInsertStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedInsertStrOrderArgs() { + ctx.delegate().testCreateNamedInsertStrOrderArgs(); + } + + @Test + @Override + public void testCreateInsertNamedArgs() { + ctx.delegate().testCreateInsertNamedArgs(); + } + + @Test + @Override + public void testCreateInsertOrderArgs() { + ctx.delegate().testCreateInsertOrderArgs(); + } + + @Test + @Override + public void testNamedInsertOrderArgs() { + ctx.delegate().testNamedInsertOrderArgs(); + } + + @Test + @Override + public void testInsertOrderArgs() { + ctx.delegate().testInsertOrderArgs(); + } + + @Test + @Override + public void testCreateNamedQueryStrStrOrderArgs() { + ctx.delegate().testCreateNamedQueryStrStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedQueryStrNamedArgs() { + ctx.delegate().testCreateNamedQueryStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedQueryStrOrderArgs() { + ctx.delegate().testCreateNamedQueryStrOrderArgs(); + } + + @Test + @Override + public void testCreateQueryNamedArgs() { + ctx.delegate().testCreateQueryNamedArgs(); + } + + @Test + @Override + public void testCreateQueryOrderArgs() { + ctx.delegate().testCreateQueryOrderArgs(); + } + + @Test + @Override + public void testNamedQueryOrderArgs() { + ctx.delegate().testNamedQueryOrderArgs(); + } + + @Test + @Override + public void testQueryOrderArgs() { + ctx.delegate().testQueryOrderArgs(); + } + + @Test + @Override + public void testCreateNamedUpdateStrStrNamedArgs() { + ctx.delegate().testCreateNamedUpdateStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedUpdateStrNamedArgs() { + ctx.delegate().testCreateNamedUpdateStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedUpdateStrOrderArgs() { + ctx.delegate().testCreateNamedUpdateStrOrderArgs(); + } + + @Test + @Override + public void testCreateUpdateNamedArgs() { + ctx.delegate().testCreateUpdateNamedArgs(); + } + + @Test + @Override + public void testCreateUpdateOrderArgs() { + ctx.delegate().testCreateUpdateOrderArgs(); + } + + @Test + @Override + public void testNamedUpdateNamedArgs() { + ctx.delegate().testNamedUpdateNamedArgs(); + } + + @Test + @Override + public void testUpdateOrderArgs() { + ctx.delegate().testUpdateOrderArgs(); + } +} diff --git a/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLSimpleRemoteTestIT.java b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLSimpleRemoteTestIT.java new file mode 100644 index 00000000000..d0607b5d7ab --- /dev/null +++ b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLSimpleRemoteTestIT.java @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.pgsql; + +import io.helidon.tests.integration.dbclient.common.SimpleTest; + +import org.junit.jupiter.api.Test; + +/** + * Remote simple test. + */ +final class PostgreSQLSimpleRemoteTestIT extends PostgreSQLRemoteTest implements SimpleTest { + + PostgreSQLSimpleRemoteTestIT() { + super("/test/simple"); + } + + @Test + @Override + public void testCreateNamedDeleteStrStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDeleteStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDeleteStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDeleteNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithInsertStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithInsertStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithInsertStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDmlWithInsertNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDmlWithInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedDmlWithInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testDmlWithInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithUpdateStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithUpdateStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithUpdateStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDmlWithUpdateNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDmlWithUpdateOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedDmlWithUpdateOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testDmlWithUpdateOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithDeleteStrStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithDeleteStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDmlWithDeleteStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDmlWithDeleteNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDmlWithDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedDmlWithDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testDmlWithDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedGetStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedGetStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedGetStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateGetNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateGetOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedGetStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testGetStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedInsertStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedInsertStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedInsertStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateInsertNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryStrStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateQueryNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateQueryOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedQueryOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testQueryOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedUpdateStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedUpdateStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedUpdateStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateUpdateNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateUpdateOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedUpdateNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testUpdateOrderArgs() { + remoteTest(); + } +} diff --git a/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLStatementLocalTestIT.java b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLStatementLocalTestIT.java new file mode 100644 index 00000000000..1b1abc46164 --- /dev/null +++ b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLStatementLocalTestIT.java @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.pgsql; + +import io.helidon.tests.integration.dbclient.common.LocalTextContext; +import io.helidon.tests.integration.dbclient.common.StatementTest; +import io.helidon.tests.integration.dbclient.common.StatementTestImpl; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Local statement test. + */ +final class PostgreSQLStatementLocalTestIT extends PostgreSQLLocalTest implements StatementTest { + + static LocalTextContext ctx; + + @BeforeAll + static void setUp() { + ctx = context(StatementTestImpl::new); + } + + @Test + @Override + public void testCreateNamedQueryNonExistentStmt() { + ctx.delegate().testCreateNamedQueryNonExistentStmt(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithoutArgs() { + ctx.delegate().testCreateNamedQueryNamedAndOrderArgsWithoutArgs(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithArgs() { + ctx.delegate().testCreateNamedQueryNamedAndOrderArgsWithArgs(); + } + + @Test + @Override + public void testCreateNamedQueryNamedArgsSetOrderArg() { + ctx.delegate().testCreateNamedQueryNamedArgsSetOrderArg(); + } + + @Test + @Override + public void testCreateNamedQueryOrderArgsSetNamedArg() { + ctx.delegate().testCreateNamedQueryOrderArgsSetNamedArg(); + } + + @Test + @Override + public void testGetArrayParams() { + ctx.delegate().testGetArrayParams(); + } + + @Test + @Override + public void testGetListParams() { + ctx.delegate().testGetListParams(); + } + + @Test + @Override + public void testGetMapParams() { + ctx.delegate().testGetMapParams(); + } + + @Test + @Override + public void testGetOrderParam() { + ctx.delegate().testGetOrderParam(); + } + + @Test + @Override + public void testGetNamedParam() { + ctx.delegate().testGetNamedParam(); + } + + @Test + @Override + public void testGetMappedNamedParam() { + ctx.delegate().testGetMappedNamedParam(); + } + + @Test + @Override + public void testGetMappedOrderParam() { + ctx.delegate().testGetMappedOrderParam(); + } + + @Test + @Override + public void testQueryArrayParams() { + ctx.delegate().testQueryArrayParams(); + } + + @Test + @Override + public void testQueryListParams() { + ctx.delegate().testQueryListParams(); + } + + @Test + @Override + public void testQueryMapParams() { + ctx.delegate().testQueryMapParams(); + } + + @Test + @Override + public void testQueryMapMissingParams() { + ctx.delegate().testQueryMapMissingParams(); + } + + @Test + @Override + public void testQueryOrderParam() { + ctx.delegate().testQueryOrderParam(); + } + + @Test + @Override + public void testQueryNamedParam() { + ctx.delegate().testQueryNamedParam(); + } + + @Test + @Override + public void testQueryMappedNamedParam() { + ctx.delegate().testQueryMappedNamedParam(); + } + + @Test + @Override + public void testQueryMappedOrderParam() { + ctx.delegate().testQueryMappedOrderParam(); + } + + @Test + @Override + public void testDmlArrayParams() { + ctx.delegate().testDmlArrayParams(); + } + + @Test + @Override + public void testDmlListParams() { + ctx.delegate().testDmlListParams(); + } + + @Test + @Override + public void testDmlMapParams() { + ctx.delegate().testDmlMapParams(); + } + + @Test + @Override + public void testDmlOrderParam() { + ctx.delegate().testDmlOrderParam(); + } + + @Test + @Override + public void testDmlNamedParam() { + ctx.delegate().testDmlNamedParam(); + } + + @Test + @Override + public void testDmlMappedNamedParam() { + ctx.delegate().testDmlMappedNamedParam(); + } + + @Test + @Override + public void testDmlMappedOrderParam() { + ctx.delegate().testDmlMappedOrderParam(); + } +} diff --git a/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLStatementRemoteTestIT.java b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLStatementRemoteTestIT.java new file mode 100644 index 00000000000..88b5a5c6c7a --- /dev/null +++ b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLStatementRemoteTestIT.java @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.pgsql; + +import io.helidon.tests.integration.dbclient.common.StatementTest; + +import org.junit.jupiter.api.Test; + +/** + * Remote statement test. + */ +final class PostgreSQLStatementRemoteTestIT extends PostgreSQLRemoteTest implements StatementTest { + + PostgreSQLStatementRemoteTestIT() { + super("/test/statement"); + } + + @Test + @Override + public void testCreateNamedQueryNonExistentStmt() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithoutArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNamedArgsSetOrderArg() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryOrderArgsSetNamedArg() { + remoteTest(); + } + + @Test + @Override + public void testGetArrayParams() { + remoteTest(); + } + + @Test + @Override + public void testGetListParams() { + remoteTest(); + } + + @Test + @Override + public void testGetMapParams() { + remoteTest(); + } + + @Test + @Override + public void testGetOrderParam() { + remoteTest(); + } + + @Test + @Override + public void testGetNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testGetMappedNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testGetMappedOrderParam() { + remoteTest(); + } + + @Test + @Override + public void testQueryArrayParams() { + remoteTest(); + } + + @Test + @Override + public void testQueryListParams() { + remoteTest(); + } + + @Test + @Override + public void testQueryMapParams() { + remoteTest(); + } + + @Test + @Override + public void testQueryMapMissingParams() { + remoteTest(); + } + + @Test + @Override + public void testQueryOrderParam() { + remoteTest(); + } + + @Test + @Override + public void testQueryNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testQueryMappedNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testQueryMappedOrderParam() { + remoteTest(); + } + + @Test + @Override + public void testDmlArrayParams() { + remoteTest(); + } + + @Test + @Override + public void testDmlListParams() { + remoteTest(); + } + + @Test + @Override + public void testDmlMapParams() { + remoteTest(); + } + + @Test + @Override + public void testDmlOrderParam() { + remoteTest(); + } + + @Test + @Override + public void testDmlNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testDmlMappedNamedParam() { + remoteTest(); + } + + @Test + @Override + public void testDmlMappedOrderParam() { + remoteTest(); + } +} diff --git a/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLTestContainer.java b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLTestContainer.java new file mode 100644 index 00000000000..35e0b295032 --- /dev/null +++ b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLTestContainer.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.pgsql; + +import java.nio.file.Path; +import java.time.Duration; +import java.time.temporal.ChronoUnit; +import java.util.Map; +import java.util.concurrent.Future; +import java.util.function.Supplier; + +import org.testcontainers.containers.JdbcDatabaseContainer; +import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; +import org.testcontainers.images.builder.ImageFromDockerfile; + +/** + * Database container utility. + */ +abstract class PostgreSQLTestContainer { + + private static final ImageFromDockerfile IMAGE = new ImageFromDockerfile("pgsql", false) + .withFileFromPath(".", Path.of("etc/docker")); + + static final JdbcDatabaseContainer CONTAINER = new PostgreSQLContainer(IMAGE) + .withPassword("pgsql123"); + + static Map> config() { + return Map.of("db.connection.url", CONTAINER::getJdbcUrl); + } + + private PostgreSQLTestContainer() { + } + + private static final class PostgreSQLContainer extends JdbcDatabaseContainer { + + private String dbName = "test"; + private String username = "test"; + private String password = "test"; + + PostgreSQLContainer(Future image) { + super(image); + waitStrategy = new LogMessageWaitStrategy() + .withRegEx(".*database system is ready to accept connections.*\\s") + .withTimes(2) + .withStartupTimeout(Duration.of(60, ChronoUnit.SECONDS)); + addExposedPort(5432); + } + + @Override + protected void configure() { + // Disable Postgres driver use of java.util.logging to reduce noise at startup time + withUrlParam("loggerLevel", "OFF"); + addEnv("POSTGRES_DB", dbName); + addEnv("POSTGRES_USER", username); + addEnv("POSTGRES_PASSWORD", password); + } + + @Override + public PostgreSQLContainer withUsername(String username) { + this.username = username; + return this; + } + + @Override + public PostgreSQLContainer withPassword(String password) { + this.password = password; + return this; + } + + @Override + public PostgreSQLContainer withDatabaseName(String dbName) { + this.dbName = dbName; + return this; + } + + @Override + public String getDriverClassName() { + return "org.postgresql.Driver"; + } + + @Override + public String getJdbcUrl() { + return "jdbc:postgresql://localhost:%d/%s".formatted(getMappedPort(5432), dbName); + } + + @Override + public String getUsername() { + return username; + } + + @Override + public String getPassword() { + return password; + } + + @Override + protected String getTestQueryString() { + return "SELECT 1"; + } + } +} diff --git a/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLTransactionLocalTestIT.java b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLTransactionLocalTestIT.java new file mode 100644 index 00000000000..9258f730340 --- /dev/null +++ b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLTransactionLocalTestIT.java @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.pgsql; + +import io.helidon.tests.integration.dbclient.common.LocalTextContext; +import io.helidon.tests.integration.dbclient.common.TransactionTest; +import io.helidon.tests.integration.dbclient.common.TransactionTestImpl; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Local transaction test. + */ +final class PostgreSQLTransactionLocalTestIT extends PostgreSQLLocalTest implements TransactionTest { + + static LocalTextContext ctx; + + @BeforeAll + static void setUp() { + ctx = context(TransactionTestImpl::new); + } + + @Test + @Override + public void testCreateNamedDeleteStrStrOrderArgs() { + ctx.delegate().testCreateNamedDeleteStrStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedDeleteStrNamedArgs() { + ctx.delegate().testCreateNamedDeleteStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedDeleteStrOrderArgs() { + ctx.delegate().testCreateNamedDeleteStrOrderArgs(); + } + + @Test + @Override + public void testCreateDeleteNamedArgs() { + ctx.delegate().testCreateDeleteNamedArgs(); + } + + @Test + @Override + public void testCreateDeleteOrderArgs() { + ctx.delegate().testCreateDeleteOrderArgs(); + } + + @Test + @Override + public void testNamedDeleteOrderArgs() { + ctx.delegate().testNamedDeleteOrderArgs(); + } + + @Test + @Override + public void testDeleteOrderArgs() { + ctx.delegate().testDeleteOrderArgs(); + } + + @Test + @Override + public void testCreateNamedQueryNonExistentStmt() { + ctx.delegate().testCreateNamedQueryNonExistentStmt(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithoutArgs() { + ctx.delegate().testCreateNamedQueryNamedAndOrderArgsWithoutArgs(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithArgs() { + ctx.delegate().testCreateNamedQueryNamedAndOrderArgsWithArgs(); + } + + @Test + @Override + public void testCreateNamedQueryNamedArgsSetOrderArg() { + ctx.delegate().testCreateNamedQueryNamedArgsSetOrderArg(); + } + + @Test + @Override + public void testCreateNamedQueryOrderArgsSetNamedArg() { + ctx.delegate().testCreateNamedQueryOrderArgsSetNamedArg(); + } + + @Test + @Override + public void testCreateNamedGetStrStrNamedArgs() { + ctx.delegate().testCreateNamedGetStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedGetStrNamedArgs() { + ctx.delegate().testCreateNamedGetStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedGetStrOrderArgs() { + ctx.delegate().testCreateNamedGetStrOrderArgs(); + } + + @Test + @Override + public void testCreateGetNamedArgs() { + ctx.delegate().testCreateGetNamedArgs(); + } + + @Test + @Override + public void testCreateGetOrderArgs() { + ctx.delegate().testCreateGetOrderArgs(); + } + + @Test + @Override + public void testNamedGetStrOrderArgs() { + ctx.delegate().testNamedGetStrOrderArgs(); + } + + @Test + @Override + public void testGetStrOrderArgs() { + ctx.delegate().testGetStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedInsertStrStrNamedArgs() { + ctx.delegate().testCreateNamedInsertStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedInsertStrNamedArgs() { + ctx.delegate().testCreateNamedInsertStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedInsertStrOrderArgs() { + ctx.delegate().testCreateNamedInsertStrOrderArgs(); + } + + @Test + @Override + public void testCreateInsertNamedArgs() { + ctx.delegate().testCreateInsertNamedArgs(); + } + + @Test + @Override + public void testCreateInsertOrderArgs() { + ctx.delegate().testCreateInsertOrderArgs(); + } + + @Test + @Override + public void testNamedInsertOrderArgs() { + ctx.delegate().testNamedInsertOrderArgs(); + } + + @Test + @Override + public void testInsertOrderArgs() { + ctx.delegate().testInsertOrderArgs(); + } + + @Test + @Override + public void testCreateNamedQueryStrStrOrderArgs() { + ctx.delegate().testCreateNamedQueryStrStrOrderArgs(); + } + + @Test + @Override + public void testCreateNamedQueryStrNamedArgs() { + ctx.delegate().testCreateNamedQueryStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedQueryStrOrderArgs() { + ctx.delegate().testCreateNamedQueryStrOrderArgs(); + } + + @Test + @Override + public void testCreateQueryNamedArgs() { + ctx.delegate().testCreateQueryNamedArgs(); + } + + @Test + @Override + public void testCreateQueryOrderArgs() { + ctx.delegate().testCreateQueryOrderArgs(); + } + + @Test + @Override + public void testNamedQueryOrderArgs() { + ctx.delegate().testNamedQueryOrderArgs(); + } + + @Test + @Override + public void testQueryOrderArgs() { + ctx.delegate().testQueryOrderArgs(); + } + + @Test + @Override + public void testCreateNamedUpdateStrStrNamedArgs() { + ctx.delegate().testCreateNamedUpdateStrStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedUpdateStrNamedArgs() { + ctx.delegate().testCreateNamedUpdateStrNamedArgs(); + } + + @Test + @Override + public void testCreateNamedUpdateStrOrderArgs() { + ctx.delegate().testCreateNamedUpdateStrOrderArgs(); + } + + @Test + @Override + public void testCreateUpdateNamedArgs() { + ctx.delegate().testCreateUpdateNamedArgs(); + } + + @Test + @Override + public void testCreateUpdateOrderArgs() { + ctx.delegate().testCreateUpdateOrderArgs(); + } + + @Test + @Override + public void testNamedUpdateNamedArgs() { + ctx.delegate().testNamedUpdateNamedArgs(); + } + + @Test + @Override + public void testUpdateOrderArgs() { + ctx.delegate().testUpdateOrderArgs(); + } +} diff --git a/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLTransactionRemoteTestIT.java b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLTransactionRemoteTestIT.java new file mode 100644 index 00000000000..9341b4a26ec --- /dev/null +++ b/tests/integration/dbclient/pgsql/src/test/java/io/helidon/tests/integration/dbclient/pgsql/PostgreSQLTransactionRemoteTestIT.java @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2024 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.tests.integration.dbclient.pgsql; + +import io.helidon.tests.integration.dbclient.common.TransactionTest; + +import org.junit.jupiter.api.Test; + +/** + * Remote transaction test. + */ +final class PostgreSQLTransactionRemoteTestIT extends PostgreSQLRemoteTest implements TransactionTest { + + PostgreSQLTransactionRemoteTestIT() { + super("/test/transaction"); + } + + @Test + @Override + public void testCreateNamedDeleteStrStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDeleteStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedDeleteStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDeleteNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testDeleteOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNonExistentStmt() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithoutArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNamedAndOrderArgsWithArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryNamedArgsSetOrderArg() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryOrderArgsSetNamedArg() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedGetStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedGetStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedGetStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateGetNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateGetOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedGetStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testGetStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedInsertStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedInsertStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedInsertStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateInsertNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testInsertOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryStrStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedQueryStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateQueryNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateQueryOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedQueryOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testQueryOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedUpdateStrStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedUpdateStrNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateNamedUpdateStrOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateUpdateNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testCreateUpdateOrderArgs() { + remoteTest(); + } + + @Test + @Override + public void testNamedUpdateNamedArgs() { + remoteTest(); + } + + @Test + @Override + public void testUpdateOrderArgs() { + remoteTest(); + } +} diff --git a/tests/integration/dbclient/pom.xml b/tests/integration/dbclient/pom.xml index 651b8247354..421cdb35b37 100644 --- a/tests/integration/dbclient/pom.xml +++ b/tests/integration/dbclient/pom.xml @@ -19,7 +19,6 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - io.helidon.tests.integration helidon-tests-integration @@ -29,34 +28,15 @@ io.helidon.tests.integration.dbclient helidon-tests-integration-dbclient-project pom - Helidon Tests Integration Database Client - A set of tests that validate Database Client + Helidon Tests Integration DbClient Project common + parent h2 - app + mysql + pgsql + oracle + mongodb - - - - - io.helidon.build-tools - helidon-services-plugin - - false - - - - - - - - testcontainers - - - - - - diff --git a/tests/integration/harness/pom.xml b/tests/integration/harness/pom.xml index 39f4843e2ad..48f75ddd04d 100644 --- a/tests/integration/harness/pom.xml +++ b/tests/integration/harness/pom.xml @@ -17,39 +17,23 @@ + 4.0.0 io.helidon.tests.integration helidon-tests-integration 4.1.0-SNAPSHOT - 4.0.0 helidon-tests-integration-harness Helidon Tests Integration Harness - - io.helidon.webclient - helidon-webclient - - - io.helidon.http.media - helidon-http-media-jsonp - - - jakarta.json - jakarta.json-api - org.junit.jupiter junit-jupiter-api - org.junit.platform - junit-platform-suite-engine - - - org.junit.platform - junit-platform-launcher + io.helidon.common + helidon-common diff --git a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/AfterSuite.java b/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/AfterSuite.java deleted file mode 100644 index e174dfb552f..00000000000 --- a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/AfterSuite.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2023 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.tests.integration.harness; - -import org.junit.platform.suite.api.Suite; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Hook for static methods invoked after a {@link Suite}. - */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface AfterSuite { - - /** - * Priority, higher value has higher priority. - * - * @return priority - */ - int priority() default 100; -} diff --git a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/AppResponse.java b/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/AppResponse.java deleted file mode 100644 index 7b4f8897a3e..00000000000 --- a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/AppResponse.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.harness; - -import jakarta.json.Json; -import jakarta.json.JsonArrayBuilder; -import jakarta.json.JsonObject; -import jakarta.json.JsonObjectBuilder; -import jakarta.json.JsonValue; - -/** - * Response helper methods. - */ -public class AppResponse { - - /** - * Build JSON response with {@code OK} status. - *

        Returned JSON object has the following structure:
        - *

         {
        -     *      "status": "OK",
        -     *      "data": <data>
        -     * }
        - * - * @param data attached data JSON value. - * @return JSON response with OK status and attached data. - */ - public static JsonObject okStatus(JsonValue data) { - JsonObjectBuilder job = Json.createObjectBuilder(); - job.add("status", "OK"); - job.add("data", data != null ? data : JsonValue.NULL); - return job.build(); - } - - /** - * Build JSON response with {@code exception} status. - *

        Returned JSON object has the following structure:
        - *

         {
        -     *      "status": "exception",
        -     *      "stacktrace": [
        -     *          {
        -     *              "class": "class.of.Exception",
        -     *              "message": "Exception message",
        -     *              "trace": [
        -     *                  {
        -     *                      "file": "Java class file",
        -     *                      line": <exception line number in Java class file>,
        -     *                      "module": "module name",
        -     *                      "modVersion": "module version",
        -     *                      "loader": "classloader name",
        -     *                      "class": "class name",
        -     *                      "method": "method name"
        -     *                  },
        -     *                  {...},...
        -     *              ]
        -     *          },
        -     *          {...},...
        -     *      ]
        -     * }
        - * - * @param th {@link Throwable} to be stored in JSON response - * @return JSON response with exception status and attached stack trace. - */ - public static JsonObject exceptionStatus(Throwable th) { - JsonObjectBuilder job = Json.createObjectBuilder(); - job.add("status", "exception"); - JsonArrayBuilder jabSt = Json.createArrayBuilder(); - Throwable current = th; - while (current != null) { - jabSt.add(buildStackTrace(current)); - current = current.getCause(); - } - job.add("stacktrace", jabSt.build()); - return job.build(); - } - - private static JsonObject buildStackTrace(Throwable t) { - JsonObjectBuilder jobSt = Json.createObjectBuilder(); - jobSt.add("class", t.getClass().getName()); - jobSt.add("message", t.getMessage()); - JsonArrayBuilder jab = Json.createArrayBuilder(); - StackTraceElement[] elements = t.getStackTrace(); - if (elements != null) { - for (StackTraceElement element : elements) { - JsonObjectBuilder jobElement = Json.createObjectBuilder(); - jobElement.add("file", element.getFileName() != null ? Json.createValue(element.getFileName()) : JsonValue.NULL); - jobElement.add("line", element.getLineNumber()); - jobElement.add("module", element.getModuleName() != null ? Json.createValue(element.getModuleName()) : JsonValue.NULL); - jobElement.add("modVersion", element.getModuleVersion() != null ? Json.createValue(element.getModuleVersion()) : JsonValue.NULL); - jobElement.add("loader", element.getClassLoaderName() != null ? Json.createValue(element.getClassLoaderName()) : JsonValue.NULL); - jobElement.add("class", Json.createValue(element.getClassName())); - jobElement.add("method", Json.createValue(element.getMethodName())); - jab.add(jobElement.build()); - } - } - jobSt.add("trace", jab.build()); - return jobSt.build(); - } - -} diff --git a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/HelidonProcessRunner.java b/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/HelidonProcessRunner.java deleted file mode 100644 index 0e528df8668..00000000000 --- a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/HelidonProcessRunner.java +++ /dev/null @@ -1,480 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.harness; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.lang.System.Logger.Level; -import java.net.InetSocketAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketAddress; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Function; -import java.util.stream.Collectors; - -/** - * Process runner to start Helidon application. - * Handles external process life cycle with various execution types. - */ -public class HelidonProcessRunner { - - private static final System.Logger LOGGER = System.getLogger(HelidonProcessRunner.class.getName()); - - /** - * HTTP port of running application. Value is set to {@code -1} before application will be started. - */ - public static int HTTP_PORT = -1; - - private final AtomicReference process = new AtomicReference<>(); - private final ExecType execType; - private final Runnable startCommand; - private final Runnable stopCommand; - private final int port; - - private HelidonProcessRunner(Builder builder) { - this.execType = builder.execType; - this.port = findFreePort(); - if (execType == ExecType.IN_MEMORY) { - this.startCommand = builder.inMemoryStartCommand; - this.stopCommand = builder.inMemoryStopCommand; - System.setProperty("server.port", String.valueOf(port)); - } else { - ProcessBuilder pb = new ProcessBuilder(); - pb.environment().put("SERVER_PORT", String.valueOf(port)); - switch (execType) { - case CLASS_PATH -> addClasspathCommand(builder, pb); - case MODULE_PATH -> addModulePathCommand(builder, pb); - case NATIVE -> addNativeCommand(builder, pb); - case JLINK_CLASS_PATH -> addJlinkCommand(builder, pb); - case JLINK_MODULE_PATH -> addJlinkModuleCommand(builder, pb); - default -> throw new IllegalArgumentException("Unsupported exec type: " + execType); - } - startCommand = () -> { - try { - // configure redirects - Thread stdoutReader = new Thread(() -> logStdout(process)); - Thread stderrReader = new Thread(() -> logStderr(process)); - - process.set(pb.start()); - - stdoutReader.start(); - stderrReader.start(); - - waitForSocketOpen(process.get(), port); - } catch (RuntimeException e) { - throw e; - } catch (Exception e) { - throw new RuntimeException("Failed to start process", e); - } - }; - stopCommand = () -> { - Process p = process.get(); - if (p == null || !p.isAlive()) { - return; - } - p.destroy(); - }; - } - } - - /** - * Create a new builder. - * - * @return builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Start the application. - * Value of {@code HTTP_PORT} is set to HTTP port of this application. - * - * @return this instance - */ - public HelidonProcessRunner startApplication() { - startCommand.run(); - HTTP_PORT = port; - return this; - } - - /** - * Return type of execution for the application. - * - * @return type of execution for the application - */ - public ExecType execType() { - return execType; - } - - /** - * Stop the application. - * Value of {@code HTTP_PORT} is set to {@code -1}. - * - * @return this instance - */ - public HelidonProcessRunner stopApplication() { - stopCommand.run(); - if (process.get() != null) { - process.get().destroy(); - } - HTTP_PORT = -1; - return this; - } - - private static void waitForSocketOpen(Process process, int port) { - long timeoutSeconds = 20; - long timeout = TimeUnit.SECONDS.toMillis(timeoutSeconds); - - long begin = System.currentTimeMillis(); - LOGGER.log(Level.TRACE, () -> String.format("Waiting for %d to listen", port)); - while (true) { - // check port open - if (portOpen(port)) { - return; - } - // make sure process still alive - if (!process.isAlive()) { - throw new RuntimeException("Process failed to start. Exit code: " + process.exitValue()); - } - // sleep - try { - TimeUnit.MILLISECONDS.sleep(150); - } catch (InterruptedException e) { - process.destroyForcibly(); - throw new RuntimeException("Cancelling process startup, thread interrupted", e); - } - // timeout - long now = System.currentTimeMillis(); - if (now - begin > timeout) { - process.destroyForcibly(); - throw new RuntimeException("Process failed to start, time out after " + timeoutSeconds + " seconds"); - } - } - } - - private static boolean portOpen(int port) { - SocketAddress sa = new InetSocketAddress("localhost", port); - try (Socket socket = new Socket()) { - socket.connect(sa, 1000); - LOGGER.log(Level.TRACE, () -> String.format("Socket localhost:%d is ready", port)); - return true; - } catch (IOException ex) { - LOGGER.log(Level.TRACE, () -> String.format("Socket localhost:%d exception: %s", port, ex.getMessage())); - return false; - } - } - - private static int findFreePort() { - int port = 7001; - - try (ServerSocket socket = new ServerSocket(0)) { - socket.setReuseAddress(true); - port = socket.getLocalPort(); - } catch (IOException e) { - LOGGER.log(Level.WARNING, "Could not find available port, using 7001", e); - } - - return port; - } - - private static void logStdout(AtomicReference process) { - BufferedReader reader = new BufferedReader( - new InputStreamReader(process.get().getInputStream())); - String line; - try { - line = reader.readLine(); - while (line != null) { - System.out.println("* " + line); - line = reader.readLine(); - } - } catch (IOException ex) { - throw new RuntimeException(ex); - } - } - - /** - * Log the process standard error. - */ - private static void logStderr(AtomicReference process) { - BufferedReader reader = new BufferedReader( - new InputStreamReader(process.get().getErrorStream())); - String line; - try { - line = reader.readLine(); - while (line != null) { - System.err.println("* " + line); - line = reader.readLine(); - } - } catch (IOException ex) { - throw new RuntimeException(ex); - } - } - - private static void addModulePathCommand(Builder builder, ProcessBuilder processBuilder) { - addModuleCommand("java", - "target", - builder.finalName, - builder.moduleName, - builder.mainClassModuleName, - builder.mainClass, - builder.args, - processBuilder); - } - - private static void addJlinkModuleCommand(Builder builder, ProcessBuilder processBuilder) { - String jriDir = "target/" + builder.finalName + "-jri"; - - // FIXME instead of java, we should use the jriDir + "/bin/start" command with a switch such as "--modules" - addModuleCommand(jriDir + "/bin/java", - jriDir + "/app", - builder.finalName, - builder.moduleName, - builder.mainClassModuleName, - builder.mainClass, - builder.args, - processBuilder); - } - - private static void addModuleCommand(String java, - String location, - String finalName, - String moduleName, - String mainClassModuleName, - String mainClass, - String[] args, - ProcessBuilder processBuilder) { - - List command = new ArrayList<>(6); - command.add(java); - command.add("--module-path"); - command.add(location + "/" + finalName + ".jar" + File.pathSeparator + "target/libs"); - command.add("--module"); - command.add(mainClassModuleName + "/" + mainClass); - - if (!Objects.equals(moduleName, mainClassModuleName)) { - // we are running main class from another module, need to add current module - command.add("--add-modules"); - command.add(moduleName); - } - - LOGGER.log(Level.DEBUG, () -> String.format("Command: %s", command)); - processBuilder.command(buildCommand(args, command)); - } - - private static void addJlinkCommand(Builder builder, ProcessBuilder processBuilder) { - String jriDir = "target/" + builder.finalName + "-jri"; - // FIXME - instead of java -jar, we should use the jriDir + "/bin/start" command - processBuilder.command( - buildCommand(builder.args, - jriDir + "/bin/java", - "-jar", - jriDir + "/app/" + builder.finalName + ".jar")); - } - - private static void addClasspathCommand(Builder builder, ProcessBuilder processBuilder) { - processBuilder.command( - buildCommand(builder.args, "java", "-jar", "target/" + builder.finalName + ".jar")); - } - - private static void addNativeCommand(Builder builder, ProcessBuilder processBuilder) { - processBuilder.command(buildCommand(builder.args, "target/" + builder.finalName)); - } - - private static List buildCommand(String[] args, String... command) { - return buildCommand(args, Arrays.asList(command)); - } - - private static List buildCommand(String[] args, List command) { - final List commandList = new LinkedList<>(command); - if (args != null) { - commandList.addAll(Arrays.asList(args)); - } - return commandList; - } - - /** - * Return HTTP port of the application. - * - * @return HTTP port of the application - */ - public int port() { - return port; - } - - /** - * Application execution types. - */ - public enum ExecType { - CLASS_PATH("classpath"), - MODULE_PATH("module"), - NATIVE("native"), - IN_MEMORY("memory"), - JLINK_CLASS_PATH("jlink-cp"), - JLINK_MODULE_PATH("jlink-module"); - - private final String name; - - ExecType(String name) { - this.name = name; - } - - @Override - public String toString() { - return name; - } - - private static final Map NAMES = Arrays.stream(ExecType.values()) - .collect(Collectors.toMap(ExecType::toString, Function.identity())); - - /** - * Get an exec type by name. - * - * @param name name - * @return ExecType - * @throws IllegalArgumentException if no exec type is found - */ - public static ExecType of(String name) { - ExecType execType = NAMES.get(name.toLowerCase()); - if (execType != null) { - return execType; - } - throw new IllegalArgumentException("Unknown execType: " + name); - } - } - - /** - * Builder for {@link HelidonProcessRunner}. - */ - public static class Builder implements io.helidon.common.Builder { - - private ExecType execType = ExecType.CLASS_PATH; - private String moduleName; - private String mainClassModuleName; - private String mainClass; - private String finalName; - private String[] args; - private Runnable inMemoryStartCommand; - private Runnable inMemoryStopCommand; - - /** - * Set the type of execution. - * - * @param execType type of execution - * @return this builder - */ - public Builder execType(ExecType execType) { - this.execType = execType; - return this; - } - - /** - * Set the name of the application module (JPMS), used for {@link ExecType#MODULE_PATH} - * - * @param moduleName module name - * @return this builder - */ - public Builder moduleName(String moduleName) { - this.moduleName = moduleName; - return this; - } - - /** - * Set the name of the module of the main class (JPMS) - used for {@link ExecType#MODULE_PATH} - * - * @param mainClassModuleName module main class - * @return this builder - */ - public Builder mainClassModuleName(String mainClassModuleName) { - this.mainClassModuleName = mainClassModuleName; - return this; - } - - /** - * Set the name of the main class to run, used for {@link ExecType#MODULE_PATH} - * - * @param mainClass main class - * @return this builder - */ - public Builder mainClass(String mainClass) { - this.mainClass = mainClass; - return this; - } - - /** - * Set the final name of the artifact. - * This is the expected name of the native image and jar file - * - * @param finalName final name - * @return this builder - */ - public Builder finalName(String finalName) { - this.finalName = finalName; - return this; - } - - /** - * Set the arguments passed to main method. - * - * @param args main args - * @return this builder - */ - public Builder args(String[] args) { - this.args = args; - return this; - } - - /** - * Set the command to start the server in memory, used for {@link ExecType#IN_MEMORY} - * - * @param inMemoryStartCommand in-memory start command - * @return this builder - */ - public Builder inMemoryStartCommand(Runnable inMemoryStartCommand) { - this.inMemoryStartCommand = inMemoryStartCommand; - return this; - } - - /** - * Set the command to stop the server in memory, used for {@link ExecType#IN_MEMORY} - * - * @param inMemoryStopCommand in-memory stop command - * @return this builder - */ - public Builder inMemoryStopCommand(Runnable inMemoryStopCommand) { - this.inMemoryStopCommand = inMemoryStopCommand; - return this; - } - - @Override - public HelidonProcessRunner build() { - if (mainClassModuleName == null) { - mainClassModuleName = moduleName; - } - return new HelidonProcessRunner(this); - } - } -} diff --git a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/HelidonTestException.java b/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/HelidonTestException.java deleted file mode 100644 index 41ea798271f..00000000000 --- a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/HelidonTestException.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.harness; - -/** - * Thrown to report error in integration test execution. - */ -public class HelidonTestException extends RuntimeException { - - /** - * Creates an instance of {@code HelidonTestException} with remote cause. - * - * @param message the detail message. The detail message is saved for - * later retrieval by the {@link #getMessage()} method. - * @param cause cause - */ - public HelidonTestException(String message, Throwable cause) { - super(message, cause); - } - - /** - * Creates an instance of {@code HelidonTestException} with no cause. - * - * @param message the detail message. The detail message is saved for - * later retrieval by the {@link #getMessage()} method. - */ - public HelidonTestException(String message) { - super(message); - } - -} diff --git a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/JsonValues.java b/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/JsonValues.java deleted file mode 100644 index c415584f1d5..00000000000 --- a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/JsonValues.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.harness; - -import jakarta.json.JsonNumber; -import jakarta.json.JsonString; -import jakarta.json.JsonValue; - -/** - * JSON values. - */ -public class JsonValues { - - /** - * Get a {@link JsonValue} as a {@link String}. - * - * @param value value - * @return String - * @throws IllegalArgumentException if the value type cannot be converted - */ - public static String asString(JsonValue value) { - return switch (value.getValueType()) { - case STRING -> ((JsonString) value).getString(); - case NULL -> null; - default -> throw new IllegalArgumentException(String.format( - "Cannot convert JSON value to String, value: '%s', type: %s", - value, value.getValueType())); - }; - } - - /** - * Get a {@link JsonValue} as a {@code long}. - * - * @param value value - * @return long - * @throws IllegalArgumentException if the value type cannot be converted - */ - public static long asLong(JsonValue value) { - return switch (value.getValueType()) { - case NUMBER -> ((JsonNumber) value).longValue(); - case STRING -> Long.parseLong(((JsonString) value).getString()); - case TRUE -> 1; - case FALSE -> 0; - default -> throw new IllegalArgumentException(String.format( - "Cannot convert JSON value to long, value: '%s', type: %s", - value, value.getValueType())); - }; - } -} diff --git a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/PathFinder.java b/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/PathFinder.java new file mode 100644 index 00000000000..ac52aec0b3b --- /dev/null +++ b/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/PathFinder.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2024 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.tests.integration.harness; + +import java.io.File; +import java.lang.System.Logger.Level; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.function.Predicate; +import java.util.stream.Stream; + +/** + * Path utility class. + */ +public class PathFinder { + + private static final System.Logger LOGGER = System.getLogger(PathFinder.class.getName()); + private static final boolean IS_WINDOWS = File.pathSeparatorChar != ':'; + private static final String PATH_ENV_VAR = "PATH"; + private static final List WINDOWS_EXECUTABLE_EXTENSIONS = List.of("exe", "bin", "bat", "cmd", "ps1"); + private static final Predicate VALID_PATH = p -> Files.exists(p) && Files.isDirectory(p); + private static final List PATH_ENTRIES = + Optional.ofNullable(System.getenv(PATH_ENV_VAR)) + .map(p -> Arrays.asList(p.split(File.pathSeparator))) + .stream() + .flatMap(Collection::stream) + .map(Path::of) + .filter(VALID_PATH) + .toList(); + + private PathFinder() { + } + + private static Path findWindowsCmd(Path dir, String cmd) { + return WINDOWS_EXECUTABLE_EXTENSIONS.stream() + .map((ext) -> dir.resolve(cmd + "." + ext)) + .filter(Files::isRegularFile) + .findFirst() + .orElse(null); + } + + private static Path findCmd(Path dir, String cmd) { + LOGGER.log(Level.DEBUG, String.format("Searching for cmd: %s in %s", cmd, dir)); + Path cmdFile = dir.resolve(cmd); + if (Files.isRegularFile(cmdFile)) { + return cmdFile; + } + return IS_WINDOWS ? findWindowsCmd(dir, cmd) : null; + } + + /** + * Find a file in the system path. + * + * @param fileName file to find + * @param envVar override + * @return optional + */ + public static Optional find(String fileName, String envVar) { + return Stream.concat( + Optional.ofNullable(System.getenv(envVar)) + .map(Path::of) + .map(p -> p.resolve("bin")) + .stream() + .filter(VALID_PATH), + PATH_ENTRIES.stream()) + .flatMap(dir -> Optional.ofNullable(findCmd(dir, fileName)).stream()) + .findFirst(); + } +} diff --git a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/ProcessMonitor.java b/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/ProcessMonitor.java new file mode 100644 index 00000000000..34db00f3377 --- /dev/null +++ b/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/ProcessMonitor.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2024 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.tests.integration.harness; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import io.helidon.common.LazyValue; + +/** + * Process monitor. + */ +public final class ProcessMonitor implements AutoCloseable { + + private static final System.Logger LOGGER = System.getLogger(ProcessMonitor.class.getName()); + private static final LazyValue SHUTDOWN = LazyValue.create(ShutdownThread::new); + private static final String PORT_REGEX = ".* http://localhost:([0-9]*) ?.*"; + private static final Pattern PORT_PATTERN = Pattern.compile(PORT_REGEX); + private static final String LINE_SEP = System.lineSeparator(); + + private final Lock outputLock = new ReentrantLock(); + private final StringBuilder output = new StringBuilder(); + private final int port; + private final Process process; + private final WaitStrategy waitStrategy; + + ProcessMonitor(ProcessBuilder pb, int port, WaitStrategy waitStrategy) { + try { + this.port = port; + this.waitStrategy = waitStrategy; + LOGGER.log(System.Logger.Level.INFO, "Executing " + String.join(" ", pb.command())); + Thread stdoutReader = new Thread(this::logStdout); + Thread stderrReader = new Thread(this::logStderr); + process = pb.start(); + SHUTDOWN.get().add(process); + stdoutReader.start(); + stderrReader.start(); + } catch (Throwable ex) { + throw new RuntimeException("Failed to start process", ex); + } + } + + @Override + public void close() { + stop(); + } + + /** + * Stop the process. + */ + public void stop() { + if (process != null && process.isAlive()) { + LOGGER.log(System.Logger.Level.INFO, "Stopping process: " + process.pid()); + process.destroy(); + SHUTDOWN.get().remove(process); + } + } + + /** + * Get the process. + * + * @return Process + */ + public Process get() { + return process; + } + + /** + * Get the process combined output. + * + * @return output + */ + public String output() { + return output.toString(); + } + + /** + * Wait for the {@link WaitStrategy strategy}. + * + * @return this instance + */ + public ProcessMonitor await() { + return await(waitStrategy); + } + + /** + * Wait for the given {@link WaitStrategy strategy}. + * + * @param waitStrategy wait strategy. + * @return this instance + */ + public ProcessMonitor await(WaitStrategy waitStrategy) { + waitStrategy.await(this, port); + return this; + } + + /** + * Get the port. + * + * @return port + */ + public int port() { + return port > 0 ? port : resolvePort(); + } + + private int resolvePort() { + return output().lines() + .map(PORT_PATTERN::matcher) + .filter(Matcher::matches) + .findFirst() + .map(m -> m.group(1)) + .map(Integer::parseInt) + .orElseThrow(() -> new IllegalStateException("Unable to find port")); + } + + private void logStdout() { + logStream(process.getInputStream(), System.out); + } + + private void logStderr() { + logStream(process.getErrorStream(), System.err); + } + + private void logStream(InputStream is, PrintStream printStream) { + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + try { + String line = reader.readLine(); + while (line != null) { + printStream.println(line); + printStream.flush(); + outputLock.lock(); + output.append(line).append(LINE_SEP); + outputLock.unlock(); + line = reader.readLine(); + } + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + + private static final class ShutdownThread extends Thread { + + private final List processes = Collections.synchronizedList(new ArrayList<>()); + + ShutdownThread() { + Runtime.getRuntime().addShutdownHook(this); + } + + void add(Process process) { + processes.add(process); + } + + void remove(Process process) { + processes.remove(process); + } + + @Override + public void run() { + // use a copy to avoid concurrent modifications + for (Process process : List.copyOf(processes)) { + if (process.isAlive()) { + LOGGER.log(System.Logger.Level.INFO, "Stopping process: " + process.pid()); + process.destroyForcibly(); + } + } + } + } +} diff --git a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/ProcessRunner.java b/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/ProcessRunner.java new file mode 100644 index 00000000000..e26fc0fe572 --- /dev/null +++ b/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/ProcessRunner.java @@ -0,0 +1,500 @@ +/* + * Copyright (c) 2021, 2024 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.tests.integration.harness; + +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.ServerSocket; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static java.util.Objects.requireNonNull; + +/** + * Fluent process runner. + */ +@SuppressWarnings("unused") +public abstract class ProcessRunner { + + private static final boolean IS_WINDOWS = File.pathSeparatorChar != ':'; + private static final Pattern VAR_PATTERN = Pattern.compile("[^$]*\\$\\{(?[^}]+)}[^$]*"); + + private final AtomicReference ref = new AtomicReference<>(); + private final List>> lazyProps = new ArrayList<>(); + private final List>> lazyEnv = new ArrayList<>(); + private final List>> lazyOpts = new ArrayList<>(); + private final List>> lazyArgs = new ArrayList<>(); + + protected String moduleName; + protected String mainModule; + protected String mainClass; + protected String finalName; + protected WaitStrategy waitStrategy = WaitStrategy.waitForCompletion(); + protected int port = -1; + + private ProcessRunner() { + } + + /** + * Execution mode. + */ + public enum ExecMode { + /** + * Execute processes using class path. + */ + CLASS_PATH, + + /** + * Execute processes using module path. + */ + MODULE_PATH, + + /** + * Execute native processes. + */ + NATIVE, + + /** + * Execute processes using the Helidon jlink start script. + */ + JLINK_CLASS_PATH, + + /** + * Execute processes using the Helidon jlink distribution with module path. + */ + JLINK_MODULE_PATH + } + + /** + * Create a new process runner. + * + * @param execMode execution mode + * @return ProcessRunner + */ + public static ProcessRunner of(ExecMode execMode) { + return switch (execMode) { + case CLASS_PATH -> new ClassPathRunner(); + case NATIVE -> new NativeImageRunner(); + case MODULE_PATH -> new ModulePathRunner(); + case JLINK_CLASS_PATH -> new JlinkRunner(); + case JLINK_MODULE_PATH -> new JlinkModulePathRunner(); + }; + } + + /** + * Get the last started process. + * + * @return ProcessMonitor + * @throws IllegalStateException if the process is not started + */ + public ProcessMonitor process() { + ProcessMonitor process = ref.get(); + if (process == null) { + throw new IllegalStateException("Process is not started"); + } + return process; + } + + /** + * Set the port. + * + * @param port port, {@code 0} overrides the configured port with a free port + * @return this instance + */ + public ProcessRunner port(int port) { + this.port = port; + return this; + } + + /** + * Set environment variables. + * + * @param env environment variables + * @return this instance + */ + public ProcessRunner env(Map env) { + return env(() -> env); + } + + /** + * Set environment variables. + * + * @param env environment variables + * @return this instance + */ + public ProcessRunner env(Supplier> env) { + this.lazyEnv.add(env); + return this; + } + + /** + * Set system properties. + * + * @param props properties + * @return this instance + */ + public ProcessRunner properties(Map props) { + return properties(() -> props); + } + + /** + * Set system properties. + * + * @param props properties + * @return this instance + */ + public ProcessRunner properties(Supplier> props) { + this.lazyProps.add(props); + return this; + } + + /** + * Set the arguments passed to main method. + * + * @param args main args + * @return this instance + */ + public ProcessRunner args(String... args) { + return args(() -> Arrays.asList(args)); + } + + /** + * Set the arguments passed to main method. + * + * @param args main args + * @return this instance + */ + public ProcessRunner args(List args) { + return args(() -> args); + } + + /** + * Set the arguments passed to main method. + * + * @param args main args + * @return this instance + */ + public ProcessRunner args(Supplier> args) { + this.lazyArgs.add(args); + return this; + } + + /** + * Set the options passed to the executable. + * + * @param opts opts + * @return this instance + */ + public ProcessRunner opts(String... opts) { + return opts(() -> Arrays.asList(opts)); + } + + /** + * Set the options passed to the executable. + * + * @param opts opts + * @return this instance + */ + public ProcessRunner opts(List opts) { + return opts(() -> opts); + } + + /** + * Set the options passed to the executable. + * + * @param opts opts + * @return this instance + */ + public ProcessRunner opts(Supplier> opts) { + this.lazyOpts.add(opts); + return this; + } + + /** + * Set the name of the application module (JPMS), used for + * {@link ProcessRunner.ExecMode#MODULE_PATH} + * + * @param moduleName module name + * @return this instance + */ + public ProcessRunner moduleName(String moduleName) { + this.moduleName = requireNonNull(moduleName, "moduleName is null"); + return this; + } + + /** + * Set the name of the module of the main class (JPMS) - used for + * {@link ProcessRunner.ExecMode#MODULE_PATH} + * + * @param mainModule main module + * @return this instance + */ + public ProcessRunner mainModule(String mainModule) { + this.mainModule = requireNonNull(mainModule, "mainModule is null"); + return this; + } + + /** + * Set the name of the main class to run, used for + * {@link ProcessRunner.ExecMode#MODULE_PATH} + * + * @param mainClass main class + * @return this instance + */ + public ProcessRunner mainClass(String mainClass) { + this.mainClass = requireNonNull(mainClass, "mainClass is null"); + return this; + } + + /** + * Set the final name of the artifact. + * This is the expected name of the native image and jar file + * + * @param finalName final name + * @return this instance + */ + public ProcessRunner finalName(String finalName) { + this.finalName = requireNonNull(finalName, "finalName is null"); + return this; + } + + /** + * Set the waiting strategy. + * + * @param waitStrategy waiting strategy + * @return this builder + * @see WaitStrategy + */ + public ProcessRunner waitingFor(WaitStrategy waitStrategy) { + this.waitStrategy = Objects.requireNonNull(waitStrategy, "waitStrategy is null"); + return this; + } + + /** + * Build the command. + * + * @param opts resolved options + * @param args resolved args + * @return command + */ + protected abstract List command(List opts, List args); + + /** + * Start the process. + * + * @return ProcessMonitor + */ + public ProcessMonitor start() { + int port = resolvePort(); + List opts = resolveOpts(port); + List args = toList(lazyArgs); + Map env = resolveEnv(port); + ProcessBuilder pb = new ProcessBuilder(command(opts, args)); + env.forEach((k, v) -> pb.environment().put(k, toString(v))); + ProcessMonitor monitor = new ProcessMonitor(pb, port, waitStrategy); + ref.set(monitor); + return monitor; + } + + private int resolvePort() { + if (port == 0) { + try (ServerSocket socket = new ServerSocket(0)) { + socket.setReuseAddress(true); + return socket.getLocalPort(); + } catch (IOException e) { + throw new UncheckedIOException("Unable to get free port", e); + } + } + return port; + } + + private Map resolveProps(int port) { + Map props = toMap(lazyProps); + if (port > 0) { + props.putIfAbsent("server.port", port); + } + return props; + } + + private Map resolveEnv(int port) { + Map env = toMap(lazyEnv); + if (port > 0) { + env.putIfAbsent("SERVER_PORT", port); + } + return env; + } + + private List resolveOpts(int port) { + List opts = toList(lazyOpts); + Map props = resolveProps(port); + resolve(props).forEach((k, v) -> opts.add("-D" + k + "=" + v)); + return opts; + } + + private static List toList(List>> lazy) { + List list = new ArrayList<>(); + lazy.forEach(m -> m.get().forEach(v -> { + if (v instanceof Supplier s) { + list.add(toString(s.get())); + } else { + list.add(toString(v)); + } + })); + return list; + } + + private static Map toMap(List>> lazy) { + Map map = new HashMap<>(); + lazy.forEach(m -> m.get().forEach((k, v) -> { + if (v instanceof Supplier s) { + map.put(k, s.get()); + } else { + map.put(k, v); + } + })); + return map; + } + + private static String toString(Object o) { + if (o instanceof Path path) { + return path.toAbsolutePath().normalize().toString(); + } + return o.toString(); + } + + private static Map resolve(Map entries) { + Map map = new HashMap<>(); + entries.forEach((k, v) -> map.put(k, resolve(toString(v), s -> toString(entries.getOrDefault(s, ""))))); + return map; + } + + private static String resolve(String str, Function function) { + StringBuilder sb = new StringBuilder(); + Matcher m = VAR_PATTERN.matcher(str); + int index = 0; + while (m.find()) { + sb.append(str, index, m.start(1) - 2); + sb.append(function.apply(m.group(1))); + index = m.end(1) + 1; + } + sb.append(str.substring(index)); + return sb.toString(); + } + + private static String javaExecutable() { + return PathFinder.find("java", "JAVA_HOME") + .map(Path::toString) + .orElseThrow(() -> new IllegalStateException("Unable to find java")); + } + + private static final class ClassPathRunner extends ProcessRunner { + + @Override + protected List command(List opts, List args) { + Objects.requireNonNull(finalName, "finalName is null"); + return new CommandBuilder(javaExecutable()) + .append(opts) + .append("-jar", Path.of("target/" + finalName + ".jar")) + .append(args) + .command(); + } + } + + private static class ModulePathRunner extends ProcessRunner { + + Path dir() { + return Path.of("target"); + } + + @Override + protected List command(List opts, List args) { + Objects.requireNonNull(mainClass, "mainClass is null"); + Objects.requireNonNull(moduleName, "moduleName is null"); + Objects.requireNonNull(finalName, "finalName is null"); + CommandBuilder cb = new CommandBuilder(javaExecutable()); + String module = mainModule != null ? mainModule : moduleName; + cb.append(opts) + .append("--module-path") + .append(dir().resolve(finalName + ".jar") + File.pathSeparator + dir().resolve("libs")) + .append("--module") + .append(module + "/" + mainClass); + if (!Objects.equals(module, moduleName)) { + // we are running main class from another module, need to add current module + cb.append("--add-modules").append(moduleName); + } + return cb.command(); + } + } + + private static final class NativeImageRunner extends ProcessRunner { + + @Override + protected List command(List opts, List args) { + Objects.requireNonNull(finalName, "finalName is null"); + return new CommandBuilder("target/" + finalName + (IS_WINDOWS ? ".exe" : "")) + .append(opts) + .append(args) + .command(); + } + } + + private static final class JlinkRunner extends ProcessRunner { + + @Override + protected List command(List opts, List args) { + Objects.requireNonNull(finalName, "finalName is null"); + return new CommandBuilder("target/" + finalName + "-jri/bin/start" + (IS_WINDOWS ? ".ps1" : "")) + .append("--jvm", String.join(" ", opts)) + .append(args) + .command(); + } + } + + private static final class JlinkModulePathRunner extends ModulePathRunner { + + @Override + protected Path dir() { + return Path.of("target/" + finalName + "-jri/app"); + } + } + + private record CommandBuilder(List command) { + + CommandBuilder(String bin) { + this(new ArrayList<>(List.of(Path.of(bin).toString()))); + } + + CommandBuilder append(List fragments) { + fragments.forEach(f -> command.add(f.toString())); + return this; + } + + CommandBuilder append(Object... fragments) { + return append(Arrays.asList(fragments)); + } + } +} diff --git a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/ProcessRunnerExtension.java b/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/ProcessRunnerExtension.java new file mode 100644 index 00000000000..b55d4dd7405 --- /dev/null +++ b/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/ProcessRunnerExtension.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2024 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.tests.integration.harness; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.List; + +import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ExtensionContext.Store.CloseableResource; + +/** + * A JUnit extension that manages the lifecycle of {@link ProcessRunner} instances annotated with {@link TestProcess}. + */ +public class ProcessRunnerExtension implements BeforeAllCallback { + + private static final ExtensionContext.Namespace NAMESPACE = ExtensionContext.Namespace.create(ProcessRunnerExtension.class); + + @Override + public void beforeAll(ExtensionContext context) throws Exception { + Class testClass = context.getRequiredTestClass(); + List runners = findProcessRunners(testClass); + ExtensionContext.Store store = context.getStore(NAMESPACE); + String key = testClass.getName(); + TestProcesses testProcesses = findTestProcesses(testClass); + List monitors = new ArrayList<>(); + if (testProcesses != null && testProcesses.parallel()) { + runners.forEach(p -> monitors.add(p.start())); + monitors.forEach(r -> store.put(key, (CloseableResource) r::close)); + monitors.forEach(ProcessMonitor::await); + } else { + //noinspection resource + runners.forEach(r -> store.put(key, (CloseableResource) r.start().await()::close)); + } + } + + private static TestProcesses findTestProcesses(Class testClass) { + for (Class clazz : allTypes(testClass)) { + if (clazz.isAnnotationPresent(TestProcesses.class)) { + return clazz.getDeclaredAnnotation(TestProcesses.class); + } + } + return null; + } + + private static List findProcessRunners(Class testClass) throws IllegalAccessException { + List runners = new ArrayList<>(); + for (Class clazz : allTypes(testClass)) { + for (Method method : clazz.getDeclaredMethods()) { + if (Modifier.isStatic(method.getModifiers()) && method.isAnnotationPresent(TestProcess.class)) { + try { + method.setAccessible(true); + Object value = method.invoke(null); + if (value instanceof ProcessRunner pr) { + runners.add(pr); + } + } catch (InvocationTargetException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + } + for (Field field : clazz.getDeclaredFields()) { + if (Modifier.isStatic(field.getModifiers()) && field.isAnnotationPresent(TestProcess.class)) { + field.setAccessible(true); + Object value = field.get(null); + if (value instanceof ProcessRunner pr) { + runners.add(pr); + } + } + } + } + return runners; + } + + private static List> allTypes(Class clazz) { + List> types = new ArrayList<>(); + Deque> stack = new ArrayDeque<>(); + stack.push(clazz); + while (!stack.isEmpty()) { + Class aClass = stack.pop(); + types.add(aClass); + Class superclass = aClass.getSuperclass(); + if (superclass != null) { + stack.push(superclass); + } + for (Class interfaceClass : aClass.getInterfaces()) { + stack.push(interfaceClass); + } + } + return types; + } +} diff --git a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/RemoteTestException.java b/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/RemoteTestException.java deleted file mode 100644 index f4114b3b73f..00000000000 --- a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/RemoteTestException.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.harness; - -/** - * Exception in remote test application. - */ -public class RemoteTestException extends RuntimeException { - - /** - * Creates an instance of remote test exception. - * - * @param message detail message - */ - public RemoteTestException(String message) { - super(message); - } - - /** - * Creates an instance of remote test exception. - * - * @param fmt formatted message - * @param args formatted message arguments - */ - public RemoteTestException(String fmt, Object... args) { - super(String.format(fmt, args)); - } -} diff --git a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/SuiteContext.java b/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/SuiteContext.java deleted file mode 100644 index 1a11dc677da..00000000000 --- a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/SuiteContext.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2023 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.tests.integration.harness; - -import java.lang.reflect.Array; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; - -/** - * Suite context. - */ -public final class SuiteContext { - - private final String id; - private final Class suiteClass; - private final CompletableFuture future = new CompletableFuture<>(); - private final Map parameters = new HashMap<>(); - - /** - * Create a new instance. - * - * @param suiteClass suite class - * @param suiteId suite id - */ - SuiteContext(Class suiteClass, String suiteId) { - this.suiteClass = suiteClass; - this.id = suiteId; - } - - /** - * Get the suite id. - * - * @return suite id - */ - public String suiteId() { - return id; - } - - /** - * Get the suite class. - * - * @return class - */ - public Class suiteClass() { - return suiteClass; - } - - /** - * Get the future. - * - * @return future - */ - public CompletionStage future() { - return future; - } - - /** - * Get the suite parameters. - * - * @return parameters - */ - public Map parameters() { - return parameters; - } - - /** - * Get the first parameter that matches the given type. - * - * @param paramType parameter type - * @param parameter type - * @return parameter value - */ - @SuppressWarnings("unchecked") - public Optional parameter(Class paramType) { - return parameters.values() - .stream() - .filter(o -> { - Class type; - if (paramType.isPrimitive()) { - type = Array.get(Array.newInstance(paramType, 1), 0).getClass(); - } else { - type = paramType; - } - return type.isAssignableFrom(o.getClass()); - }) - .map(o -> (T) o) - .findFirst(); - } -} diff --git a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/SuiteFinder.java b/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/SuiteFinder.java deleted file mode 100644 index aef316f82b4..00000000000 --- a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/SuiteFinder.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2023 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.tests.integration.harness; - -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; - -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.platform.engine.TestExecutionResult; -import org.junit.platform.engine.support.descriptor.ClassSource; -import org.junit.platform.launcher.TestExecutionListener; -import org.junit.platform.launcher.TestIdentifier; -import org.junit.platform.suite.api.Suite; - -/** - * A {@link TestExecutionListener} that identifies {@link Suite}. - */ -public class SuiteFinder implements TestExecutionListener { - - private static final Map INFOS = new HashMap<>(); - - /** - * Get a suite info for a test id. - * - * @param id test id - * @return suite info - */ - public static Optional findSuite(String id) { - return Optional.ofNullable(INFOS.get(id)) - .flatMap(suiteContext -> { - String suiteId = suiteContext.suiteId(); - if (!suiteId.equals(id)) { - return Optional.of(INFOS.get(suiteId)); - } - return Optional.of(suiteContext); - }); - } - - /** - * Get a suite info for an extension context. - * - * @param context extension context - * @return suite info - */ - public static Optional findSuite(ExtensionContext context) { - String suiteId = context.getParent().map(ExtensionContext::getUniqueId).orElse("?"); - return findSuite(suiteId); - } - - @Override - public void executionStarted(TestIdentifier testIdentifier) { - Class clazz = suiteClass(testIdentifier); - String id = testIdentifier.getUniqueId(); - if (clazz != null) { - INFOS.put(id, new SuiteContext(clazz, id)); - } else { - testIdentifier.getParentId().ifPresent(parentId -> { - SuiteContext suiteContext = INFOS.get(parentId); - if (suiteContext != null) { - INFOS.put(id, suiteContext); - } - }); - } - } - - @Override - public void executionFinished(TestIdentifier testIdentifier, TestExecutionResult testExecutionResult) { - String id = testIdentifier.getUniqueId(); - SuiteContext suiteContext = INFOS.get(testIdentifier.getUniqueId()); - if (suiteContext != null) { - if (suiteContext.suiteId().equals(id)) { - suiteContext.future().toCompletableFuture().complete(null); - } - } - } - - private static Class suiteClass(TestIdentifier testIdentifier) { - return testIdentifier.getSource() - .filter(ClassSource.class::isInstance) - .map(ClassSource.class::cast) - .map(ClassSource::getJavaClass) - .filter(source -> source.getAnnotation(Suite.class) != null) - .orElse(null); - } -} diff --git a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/SuiteLifeCycle.java b/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/SuiteLifeCycle.java deleted file mode 100644 index d39c628502c..00000000000 --- a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/SuiteLifeCycle.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (c) 2023 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.tests.integration.harness; - -import java.lang.annotation.Annotation; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.lang.reflect.Parameter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.function.ToIntFunction; - -import org.junit.jupiter.api.extension.BeforeAllCallback; -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.api.extension.ExtensionContext.Store; - -import static java.util.Comparator.comparingInt; -import static org.junit.jupiter.api.extension.ExtensionContext.Namespace.GLOBAL; - -/** - * An {@link BeforeAllCallback} extension that supports {@link BeforeSuite} and {@link AfterSuite}. - */ -public class SuiteLifeCycle implements BeforeAllCallback { - - private static final String STORE_KEY = SuiteLifeCycle.class.getName(); - private static final Comparator> BS_COMPARATOR = - comparator(BeforeSuite.class, value -> value.annotation().priority()); - private static final Comparator> AS_COMPARATOR = - comparator(AfterSuite.class, value -> value.annotation().priority()); - private static final Comparator> SETUP_COMPARATOR = - comparator(SetUp.class, value -> value.annotation().priority()); - - @Override - public void beforeAll(ExtensionContext context) { - SuiteFinder.findSuite(context).ifPresent(suiteContext -> { - Store store = context.getRoot().getStore(GLOBAL); - Object flag = store.get(STORE_KEY); - if (flag == null) { - store.put(STORE_KEY, this); - invokeBeforeSuite(suiteContext); - suiteContext.future().thenRun(() -> invokeAfterSuite(suiteContext)); - } - context.getTestClass().ifPresent( - clazz -> Arrays.stream(clazz.getMethods()) - .filter(method -> method.isAnnotationPresent(SetUp.class)) - .forEach(method -> handleSetUp(suiteContext, method)) - ); - }); - } - - private void handleBeforeSuite(SuiteContext context, Method method) { - Object value = invoke(BeforeSuite.class, method); - if (value instanceof Map map) { - Map params = context.parameters(); - map.forEach((k, v) -> params.put(k.toString(), v)); - } - } - - private void handleAfterSuite(SuiteContext context, Method method) { - invoke(AfterSuite.class, method, resolveParameters(context, method)); - } - - private void handleSetUp(SuiteContext context, Method method) { - invoke(SetUp.class, method, resolveParameters(context, method)); - } - - private void invokeBeforeSuite(SuiteContext suiteContext) { - findHandlers(suiteContext.suiteClass(), BeforeSuite.class) - .stream() - .sorted(BS_COMPARATOR) - .map(Handler::method) - .forEach(method -> handleBeforeSuite(suiteContext, method)); - } - - private void invokeAfterSuite(SuiteContext suiteContext) { - findHandlers(suiteContext.suiteClass(), AfterSuite.class) - .stream() - .sorted(AS_COMPARATOR) - .map(Handler::method) - .forEach(method -> handleAfterSuite(suiteContext, method)); - } - - private void invokeSetUp(SuiteContext suiteContext) { - findHandlers(suiteContext.suiteClass(), SetUp.class) - .stream() - .sorted(SETUP_COMPARATOR) - .map(Handler::method) - .forEach(method -> handleSetUp(suiteContext, method)); - } - - private static Object[] resolveParameters(SuiteContext context, Method method) { - List paramValues = new ArrayList<>(); - for (Parameter parameter : method.getParameters()) { - Class paramType = parameter.getType(); - Object paramValue = context.parameter(paramType) - .orElseThrow(() -> new IllegalArgumentException(String.format( - "Method %s has a parameter %s that is not supported", - method, paramType))); - paramValues.add(paramValue); - } - return paramValues.toArray(new Object[0]); - } - - private static Object invoke(Class annotationClass, Method method, Object... args) { - try { - method.setAccessible(true); - return method.invoke(null, args); - } catch (IllegalAccessException | InvocationTargetException ex) { - throw new IllegalStateException(String.format( - "Cannot invoke %s method", - annotationClass.getSimpleName()), - ex); - } - } - - private static List> findHandlers(Class clazz, Class annotationClass) { - LinkedList> handlers = new LinkedList<>(); - LinkedList> hierarchy = new LinkedList<>(); - Class analyzedClass = clazz; - while (analyzedClass != null && !analyzedClass.equals(Object.class)) { - hierarchy.addFirst(analyzedClass); - analyzedClass = analyzedClass.getSuperclass(); - } - for (Class aClass : hierarchy) { - for (Method method : aClass.getDeclaredMethods()) { - T annotation = method.getDeclaredAnnotation(annotationClass); - if (annotation != null) { - if (Modifier.isStatic(method.getModifiers())) { - handlers.add(new Handler<>(annotation, method)); - } else { - throw new IllegalStateException("Method " + method + " is annotated with " - + annotationClass.getSimpleName() - + " yet it is not static"); - } - } - } - } - return handlers; - } - - private static Comparator> comparator(Class ignored, - ToIntFunction> function) { - return comparingInt(function); - } - - private record Handler(T annotation, Method method) { - } -} diff --git a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/SuiteParameterResolver.java b/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/SuiteParameterResolver.java deleted file mode 100644 index 3e06279bee9..00000000000 --- a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/SuiteParameterResolver.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2023 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.tests.integration.harness; - -import java.lang.reflect.Parameter; - -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.api.extension.ParameterContext; -import org.junit.jupiter.api.extension.ParameterResolutionException; -import org.junit.jupiter.api.extension.ParameterResolver; -import org.junit.platform.suite.api.Suite; - -/** - * A {@link ParameterResolver} to support {@link Suite}. - */ -public class SuiteParameterResolver implements ParameterResolver { - - @Override - public boolean supportsParameter(ParameterContext parameterContext, - ExtensionContext extensionContext) throws ParameterResolutionException { - - Class paramType = parameterContext.getParameter().getType(); - return SuiteFinder.findSuite(extensionContext) - .map(suite -> suite.parameter(paramType).isPresent()) - .orElse(false); - } - - @Override - public Object resolveParameter(ParameterContext parameterContext, - ExtensionContext extensionContext) throws ParameterResolutionException { - - Parameter parameter = parameterContext.getParameter(); - Class paramType = parameter.getType(); - return SuiteFinder.findSuite(extensionContext) - .flatMap(suite -> suite.parameter(paramType)) - .orElseThrow(() -> new ParameterResolutionException("Unable to resolve parameter: " + parameter)); - } -} diff --git a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/TestClient.java b/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/TestClient.java deleted file mode 100644 index aa96b08b3c7..00000000000 --- a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/TestClient.java +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.harness; - -import java.io.StringReader; -import java.io.UnsupportedEncodingException; -import java.lang.System.Logger.Level; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.time.Duration; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -import io.helidon.common.media.type.MediaTypes; -import io.helidon.http.media.jsonp.JsonpSupport; -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientRequest; - -import jakarta.json.Json; -import jakarta.json.JsonArray; -import jakarta.json.JsonException; -import jakarta.json.JsonObject; -import jakarta.json.JsonReader; -import jakarta.json.JsonString; -import jakarta.json.JsonValue; -import org.junit.jupiter.api.Assertions; - -/** - * Web client to access all services of remote test application. - */ -public class TestClient { - - private static final System.Logger LOGGER = System.getLogger(TestClient.class.getName()); - private static final String UTF_8_STR = StandardCharsets.UTF_8.toString(); - - private final Http1Client webClient; - - TestClient(Http1Client webClient) { - this.webClient = webClient; - } - - Http1ClientRequest clientGetBuilderWithPath(String service, String method) { - StringBuilder sb = new StringBuilder(service.length() + (method != null ? method.length() : 0) + 2); - sb.append('/'); - sb.append(service); - if (method != null) { - sb.append('/'); - sb.append(method); - } - return webClient.get(sb.toString()); - } - - private static String encode(String str) { - try { - return URLEncoder.encode(str, UTF_8_STR); - } catch (UnsupportedEncodingException ex) { - Assertions.fail(String.format("URL fragment encoding failed: %s", ex.getMessage())); - } - return ""; - } - - private static Exception deserialize(JsonObject response) { - Exception root = null; - Exception ex = null; - JsonArray stackTraces = response.getJsonArray("stacktrace"); - for (JsonObject stackTrace : stackTraces.getValuesAs(JsonObject.class)) { - List elements = new ArrayList<>(); - for (JsonObject elt : stackTrace.getJsonArray("trace").getValuesAs(JsonObject.class)) { - elements.add(new StackTraceElement( - toString(elt.get("class")), - toString(elt.get("method")), - toString(elt.get("file")), - elt.getInt("line"))); - } - Exception cause = new Exception(String.format("Deserialized: class=%s, message=%s", - toString(stackTrace.get("class")), toString(stackTrace.get("message")))); - cause.setStackTrace(elements.toArray(new StackTraceElement[0])); - if (ex == null) { - root = cause; - } else { - ex.initCause(cause); - } - ex = cause; - } - return root; - } - - private static String toString(JsonValue value) { - if (value.getValueType() == JsonValue.ValueType.STRING) { - return ((JsonString) value).getString(); - } - return "?"; - } - - /** - * Creates new web client builder instance. - * - * @return new web client builder instance - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Call remote test service method and return its data. - * - * @param service remote service name - * @param method remote test method name - * @param params remote test method query parameters - * @return data returned by remote test service method - */ - public JsonValue callServiceAndGetData(String service, String method, Map params) { - return evaluateServiceCallResult( - callService( - clientGetBuilderWithPath(service, method), - params)); - } - - /** - * Call remote test service method and return its data. - * No query parameters are passed. - * - * @param service remote service name - * @param method remote test method name - * @return data returned by remote test service method - */ - public JsonValue callServiceAndGetData(String service, String method) { - return callServiceAndGetData(service, method, null); - } - - /** - * Call remote service method and return its raw data as JSON object. - * No response content check is done. - * - * @param service remote service name - * @param method remote test method name - * @param params remote test method query parameters - * @return data returned by remote service - */ - public JsonObject callServiceAndGetRawData(String service, String method, Map params) { - Http1ClientRequest rb = clientGetBuilderWithPath(service, method); - rb.headers().accept(MediaTypes.APPLICATION_JSON); - return callService(rb, params); - } - - /** - * Call remote service method and return its raw data as JSON object. - * No response content check is done. No query parameters are passed. - * - * @param service remote service name - * @param method remote test method name - * @return data returned by remote service - */ - public JsonObject callServiceAndGetRawData(String service, String method) { - return callServiceAndGetRawData(service, method, null); - } - - JsonObject callService(Http1ClientRequest clientRequest, Map params) { - if (params != null && !params.isEmpty()) { - for (Map.Entry entry : params.entrySet()) { - clientRequest.queryParam(entry.getKey(), encode(entry.getValue())); - } - } - String response = clientRequest.requestEntity(String.class); - try { - JsonReader jsonReader = Json.createReader(new StringReader(response)); - JsonValue jsonContent = jsonReader.read(); - if (Objects.requireNonNull(jsonContent.getValueType()) == JsonValue.ValueType.OBJECT) { - return jsonContent.asJsonObject(); - } - throw new HelidonTestException( - String.format( - "Expected JSON object, but got JSON %s", - jsonContent.getValueType().name().toLowerCase())); - } catch (JsonException t) { - LOGGER.log(Level.WARNING, () -> String.format("Caught %s when parsing response: %s", - t.getClass().getSimpleName(), - response), t); - throw new HelidonTestException( - String.format( - "Caught %s when parsing response: %s", - t.getClass().getSimpleName(), - response), - t); - } - } - - JsonValue evaluateServiceCallResult(JsonObject data) { - String status = data.getString("status"); - switch (status) { - case "OK" -> { - return data.get("data"); - } - case "exception" -> throw new HelidonTestException("Remote test execution failed.", deserialize(data)); - default -> throw new HelidonTestException("Unknown response content: " + data); - } - } - - /** - * Remote test web client builder. - */ - public static class Builder { - - @SuppressWarnings("HttpUrlsUsage") - private static final String HTTP_PREFIX = "http://"; - - private String host; - private int port; - - Builder() { - this.host = "localhost"; - this.port = 8080; - } - - /** - * Set test application URL host. - * - * @param host test application URL host - * @return updated {@code TestClient} builder instance - */ - public Builder host(String host) { - this.host = host; - return this; - } - - /** - * Set test application URL port. - * - * @param port test application URL port - * @return updated {@code TestClient} builder instance - */ - public Builder port(int port) { - this.port = port; - return this; - } - - /** - * Set test application URL service. - * Setting service name will result in building extended test client - * with service name support. - * - * @param service test application URL service - * @return updated {@code TestServiceClient} builder instance - */ - public TestServiceClient.Builder service(String service) { - return new TestServiceClient.Builder(this, service); - } - - /** - * Builds web client initialized with parameters stored in this builder. - * - * @return new {@link Http1Client} instance - */ - Http1Client buildWebClient() { - return Http1Client.builder() - .baseUri(HTTP_PREFIX + host + ':' + port) - .readTimeout(Duration.ofMinutes(10)) - .addMediaSupport(JsonpSupport.create()) - .build(); - } - - /** - * Builds test web client initialized with parameters stored in this builder. - * - * @return new {@link TestClient} instance - */ - public TestClient build() { - return new TestClient(buildWebClient()); - } - } -} diff --git a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/SetUp.java b/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/TestProcess.java similarity index 70% rename from tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/SetUp.java rename to tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/TestProcess.java index 03afcf6f144..acdf0508c76 100644 --- a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/SetUp.java +++ b/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/TestProcess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2024 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. @@ -21,16 +21,13 @@ import java.lang.annotation.Target; /** - * Hook for static methods invoked before all tests. + * The {@code @TestProcess} annotation is used to mark {@link ProcessRunner} instances that should be managed + * by {@link ProcessRunnerExtension}. + * + * @see ProcessRunnerExtension + * @see ProcessRunner */ -@Target(ElementType.METHOD) +@Target({ ElementType.FIELD, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) -public @interface SetUp { - - /** - * Priority, higher value has higher priority. - * - * @return priority - */ - int priority() default 100; +public @interface TestProcess { } diff --git a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/BeforeSuite.java b/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/TestProcesses.java similarity index 62% rename from tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/BeforeSuite.java rename to tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/TestProcesses.java index 2cdb15573ec..cacc68dc712 100644 --- a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/BeforeSuite.java +++ b/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/TestProcesses.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2024 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. @@ -15,24 +15,27 @@ */ package io.helidon.tests.integration.harness; -import org.junit.platform.suite.api.Suite; - import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.junit.jupiter.api.extension.ExtendWith; + /** - * Hook for static methods invoked before a {@link Suite}. + * {@code TestProcesses} enables and provides configuration for {@link ProcessRunnerExtension}. */ -@Target(ElementType.METHOD) +@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) -public @interface BeforeSuite { +@ExtendWith(ProcessRunnerExtension.class) +@Inherited +public @interface TestProcesses { /** - * Priority, higher value has higher priority. + * Whether processes start in parallel. Defaults to {@code false}. * - * @return priority + * @return if the processes should start in parallel */ - int priority() default 100; + boolean parallel() default false; } diff --git a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/TestServiceClient.java b/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/TestServiceClient.java deleted file mode 100644 index c81d0d3358c..00000000000 --- a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/TestServiceClient.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2021, 2023 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.tests.integration.harness; - -import java.util.Map; - -import io.helidon.webclient.http1.Http1Client; -import io.helidon.webclient.http1.Http1ClientRequest; - -import jakarta.json.JsonValue; - -/** - * Web client to access specific service of remote test application. - * Common service access method is still available. - */ -public class TestServiceClient extends TestClient { - - private final String service; - - private TestServiceClient(Http1Client client, String service) { - super(client); - this.service = service; - } - - /** - * Call remote test service method and return its data. - * Using service name provided to test web client builder. - * - * @param method remote test method name - * @param params remote test method query parameters - * @return data returned by remote test service method - */ - public JsonValue callServiceAndGetData(String method, Map params) { - return evaluateServiceCallResult(callService(clientGetBuilderWithPath(service, method), params)); - } - - /** - * Call remote test service method and return its data. - * Using service name provided to test web client builder. - * No query parameters are passed. - * - * @param method remote test method name - * @return data returned by remote test service method - */ - public JsonValue callServiceAndGetData(String method) { - return callServiceAndGetData(method, (Map) null); - } - - /** - * Call remote service method and return its raw data as JSON object. - * No response content check is done. No query parameters are passed. - * - * @param method remote test method name - * @return data returned by remote service - */ - public String callServiceAndGetString(String method) { - Http1ClientRequest clientRequest = clientGetBuilderWithPath(service, method); - return clientRequest.requestEntity(String.class); - } - - /** - * Remote test web client builder. - */ - public static class Builder { - - private final TestClient.Builder parentBuilder; - private final String service; - - Builder(TestClient.Builder parentBuilder, String service) { - this.parentBuilder = parentBuilder; - this.service = service; - } - - /** - * Set test application URL host. - * - * @param host test application URL host - * @return updated builder instance - */ - public Builder host(String host) { - parentBuilder.host(host); - return this; - } - - /** - * Set test application URL port. - * - * @param port test application URL port - * @return updated builder instance - */ - public Builder port(int port) { - parentBuilder.port(port); - return this; - } - - /** - * Builds test web client initialized with parameters stored in this builder. - * - * @return new {@link TestServiceClient} instance - */ - public TestServiceClient build() { - return new TestServiceClient(parentBuilder.buildWebClient(), service); - } - - } - -} diff --git a/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/WaitStrategy.java b/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/WaitStrategy.java new file mode 100644 index 00000000000..3ec4d51bdb0 --- /dev/null +++ b/tests/integration/harness/src/main/java/io/helidon/tests/integration/harness/WaitStrategy.java @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2024 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.tests.integration.harness; + +import java.io.IOException; +import java.lang.System.Logger.Level; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.time.Duration; +import java.util.Objects; + +/** + * Wait strategy. + */ +@SuppressWarnings("unused") +public sealed abstract class WaitStrategy { + + private static final System.Logger LOGGER = System.getLogger(WaitStrategy.class.getName()); + private static final String PORT_REGEX = ".* http://localhost:([0-9]*) ?.*"; + + private long timeout = 60; + + private WaitStrategy() { + } + + /** + * Wait for the configured port to be open. + * + * @return WaitStrategy + */ + public static WaitStrategy waitForPort() { + return new ConfiguredPortWaitStrategy(); + } + + /** + * Wait for the given port to be open. + * + * @return WaitStrategy + */ + public static WaitStrategy waitForPort(int port) { + return new PortWaitStrategy(port); + } + + /** + * Wait for the process to complete. + * + * @return WaitStrategy + */ + public static WaitStrategy waitForCompletion() { + return new CompletionWaitStrategy(); + } + + /** + * Wait for the given regex to match in the standard output. + * + * @param regex regex + * @return WaitStrategy + */ + public static WaitStrategy waitForLine(String regex) { + return new RegexWaitStrategy(regex); + } + + @SuppressWarnings("BusyWait") + void await(ProcessMonitor monitor, int port) { + Process process = monitor.get(); + long pid = process.pid(); + String description = toString(monitor, port); + LOGGER.log(Level.INFO, String.format("Waiting for %s, pid=%d", description, pid)); + long timeoutMillis = timeout * 1000; + long startTime = System.currentTimeMillis(); + while (process.isAlive() && System.currentTimeMillis() - startTime < timeoutMillis) { + if (test(monitor, port)) { + LOGGER.log(Level.INFO, "Process ready, pid=" + pid); + return; + } + try { + Thread.sleep(500L); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + if (test(monitor, port)) { + LOGGER.log(Level.INFO, "Process ready, pid=" + pid); + } else if (!process.isAlive()) { + throw new IllegalStateException("Process is not alive"); + } else { + throw new RuntimeException(String.format("Timeout waiting for %s, pid=%d", description, pid)); + } + } + + /** + * Test the strategy. + * + * @param monitor process monitor + * @param configuredPort configured port + * @return {@code true} if wait condition is sucessful + */ + abstract boolean test(ProcessMonitor monitor, int configuredPort); + + /** + * Get the strategy description. + * + * @param monitor process monitor + * @param configuredPort configured port + * @return description + */ + abstract String toString(ProcessMonitor monitor, int configuredPort); + + /** + * Set the timeout. + * + * @param timeout timeout + */ + public void timeout(Duration timeout) { + this.timeout = Objects.requireNonNull(timeout, "timeout is null").toSeconds(); + } + + /** + * Get the timeout in seconds. + * + * @return timeout + */ + public long timeout() { + return timeout; + } + + private static boolean isPortOpen(int port) { + SocketAddress sa = new InetSocketAddress("localhost", port); + try (Socket socket = new Socket()) { + socket.connect(sa, 1000); + LOGGER.log(Level.TRACE, "Socket localhost:%d is ready", port); + return true; + } catch (IOException ex) { + LOGGER.log(Level.TRACE, "Socket localhost:%d exception: %s", port, ex.getMessage()); + return false; + } + } + + private static boolean matchLines(String output, String regex) { + return output.lines().anyMatch(line -> line.matches(regex)); + } + + private static final class PortWaitStrategy extends WaitStrategy { + + private final int port; + + PortWaitStrategy(int port) { + this.port = port; + } + + @Override + public boolean test(ProcessMonitor monitor, int ignored) { + return isPortOpen(port); + } + + @Override + String toString(ProcessMonitor monitor, int ignored) { + return "port " + port; + } + } + + private static final class ConfiguredPortWaitStrategy extends WaitStrategy { + + @Override + public boolean test(ProcessMonitor monitor, int port) { + return port > 0 ? isPortOpen(port) : matchLines(monitor.output(), PORT_REGEX); + } + + @Override + String toString(ProcessMonitor monitor, int port) { + return port > 0 ? "port " + port : "regex " + PORT_REGEX; + } + } + + private static final class CompletionWaitStrategy extends WaitStrategy { + + @Override + public boolean test(ProcessMonitor monitor, int port) { + return !monitor.get().isAlive(); + } + + @Override + String toString(ProcessMonitor monitor, int port) { + return "completion"; + } + } + + private static final class RegexWaitStrategy extends WaitStrategy { + + private final String regex; + + private RegexWaitStrategy(String regex) { + this.regex = regex; + } + + @Override + public boolean test(ProcessMonitor monitor, int port) { + return matchLines(monitor.output(), regex); + } + + @Override + String toString(ProcessMonitor monitor, int port) { + return "regex " + regex; + } + } +} From 4d518712fbb6fe0527fb7e7d044476b80252826e Mon Sep 17 00:00:00 2001 From: Santiago Pericas-Geertsen Date: Tue, 6 Aug 2024 15:17:44 -0400 Subject: [PATCH 34/37] Upgrades gRPC dependencies to latest versions. Drops dependency with protobuf lite in favor of the full version which we already depended on. (#9105) --- dependencies/pom.xml | 4 ++-- grpc/core/src/main/java/module-info.java | 1 - .../grpc/server/src/main/java/module-info.java | 1 - .../io/helidon/webserver/grpc/ProtoMarshaller.java | 12 ++++++------ 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/dependencies/pom.xml b/dependencies/pom.xml index cc8c1d3e252..9e2b2bc756a 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -53,12 +53,12 @@ 1.34.1 1.33.3 2.3.3 - 3.21.7 + 4.27.3 23.1.0 18.6 18.3 2.9.0 - 1.60.0 + 1.65.1 32.0.1-jre 2.2.220 1.3 diff --git a/grpc/core/src/main/java/module-info.java b/grpc/core/src/main/java/module-info.java index f2866601099..930d44df09a 100644 --- a/grpc/core/src/main/java/module-info.java +++ b/grpc/core/src/main/java/module-info.java @@ -28,7 +28,6 @@ requires transitive io.grpc.stub; requires transitive com.google.protobuf; requires transitive io.grpc.protobuf; - requires transitive io.grpc.protobuf.lite; exports io.helidon.grpc.core; } diff --git a/microprofile/grpc/server/src/main/java/module-info.java b/microprofile/grpc/server/src/main/java/module-info.java index 71e2659d08f..c01fcb3b9d5 100644 --- a/microprofile/grpc/server/src/main/java/module-info.java +++ b/microprofile/grpc/server/src/main/java/module-info.java @@ -39,7 +39,6 @@ requires io.helidon.webserver.grpc; requires io.grpc; - requires io.grpc.protobuf.lite; requires com.google.protobuf; requires microprofile.health.api; diff --git a/webserver/grpc/src/main/java/io/helidon/webserver/grpc/ProtoMarshaller.java b/webserver/grpc/src/main/java/io/helidon/webserver/grpc/ProtoMarshaller.java index a3733e82db6..4908f2c8880 100644 --- a/webserver/grpc/src/main/java/io/helidon/webserver/grpc/ProtoMarshaller.java +++ b/webserver/grpc/src/main/java/io/helidon/webserver/grpc/ProtoMarshaller.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. + * Copyright (c) 2022, 2024 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. @@ -19,9 +19,9 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import com.google.protobuf.MessageLite; +import com.google.protobuf.Message; import io.grpc.MethodDescriptor; -import io.grpc.protobuf.lite.ProtoLiteUtils; +import io.grpc.protobuf.ProtoUtils; final class ProtoMarshaller { private static final Map, MethodDescriptor.Marshaller> CACHE = new ConcurrentHashMap<>(); @@ -35,12 +35,12 @@ static MethodDescriptor.Marshaller get(Class clazz) { if (result != null) { return result; } - // i may create it twice, but that should not really matter + // it may create it twice, but that should not really matter try { java.lang.reflect.Method getDefaultInstance = clazz.getDeclaredMethod("getDefaultInstance"); - MessageLite instance = (MessageLite) getDefaultInstance.invoke(clazz); + Message instance = (Message) getDefaultInstance.invoke(clazz); - result = (MethodDescriptor.Marshaller) ProtoLiteUtils.marshaller(instance); + result = (MethodDescriptor.Marshaller) ProtoUtils.marshaller(instance); MethodDescriptor.Marshaller current = (MethodDescriptor.Marshaller) CACHE.putIfAbsent(clazz, result); return current == null ? result : current; } catch (ReflectiveOperationException e) { From 90a234949cbf56f4d87c2cf3e89ce50c85854da5 Mon Sep 17 00:00:00 2001 From: Romain Grecourt Date: Tue, 6 Aug 2024 16:08:07 -0700 Subject: [PATCH 35/37] Packaging Integration Tests (#9106) Refactor tests/integration/native-image into a more general "packaging" test suite. --- .github/workflows/validate.yml | 85 ++++++- etc/scripts/test-packaging-jar.sh | 75 ------ etc/scripts/test-packaging-jlink.sh | 85 ------- etc/scripts/test-packaging-native.sh | 82 ------ tests/integration/native-image/mp-1/README.md | 40 --- tests/integration/native-image/mp-1/pom.xml | 117 --------- .../native-image.properties | 20 -- tests/integration/native-image/mp-2/README.md | 25 -- tests/integration/native-image/mp-3/README.md | 21 -- tests/integration/native-image/mp-3/pom.xml | 87 ------- tests/integration/native-image/se-1/pom.xml | 119 --------- tests/integration/packaging/mp-1/README.md | 44 ++++ .../mp-1/logging.properties | 2 +- .../mp-1/mp-config-test.yaml | 2 +- .../mp-1/mp-config.yaml | 2 +- tests/integration/packaging/mp-1/pom.xml | 227 +++++++++++++++++ .../packaging}/mp1/AutoFilter.java | 4 +- .../packaging}/mp1/BasicAuthApplication.java | 4 +- .../integration/packaging}/mp1/BeanClass.java | 4 +- .../packaging}/mp1/BeanProducer.java | 6 +- .../packaging}/mp1/JaxRsApplicationCdi.java | 4 +- .../packaging}/mp1/JaxRsApplicationNoCdi.java | 4 +- .../mp1/JaxRsApplicationNoClasses.java | 4 +- .../mp1/JaxRsProtectedResource.java | 4 +- .../packaging}/mp1/JaxRsResource.java | 4 +- .../packaging}/mp1/JwtAuthApplication.java | 4 +- .../packaging}/mp1/LivenessHealthcheck.java | 4 +- .../integration/packaging}/mp1/Mp1Main.java | 8 +- .../packaging}/mp1/OidcApplication.java | 4 +- .../packaging}/mp1/ReadinessHealthcheck.java | 4 +- .../packaging}/mp1/RestClientIface.java | 4 +- .../integration/packaging}/mp1/TestBean.java | 8 +- .../integration/packaging}/mp1/TestDto.java | 4 +- .../packaging}/mp1/other/BeanProcessor.java | 4 +- .../packaging}/mp1/other/ProducedBean.java | 4 +- .../packaging}/mp1/other/package-info.java | 4 +- .../packaging/mp1}/package-info.java | 6 +- .../mp-1/src/main/java/module-info.java | 16 +- .../src/main/resources/META-INF/beans.xml | 0 .../microprofile-config-test.properties | 2 +- .../META-INF/microprofile-config.properties | 4 +- .../native-image.properties | 2 +- .../src/main/resources/logging.properties | 2 +- .../src/main/resources/mp-meta-config.yaml | 4 +- .../mp-1/src/main/resources/sign-jwk.json | 0 .../mp-1/src/main/resources/verify-jwk.json | 0 .../mp-1/src/main/resources/web/resource.txt | 0 .../mp-1/src/main/resources/web/welcome.txt | 0 .../packaging/mp1/Mp1JarClassPathTestIT.java | 33 +++ .../packaging/mp1/Mp1JarModulePathTestIT.java | 33 +++ .../mp1/Mp1JlinkModulePathTestIT.java | 33 +++ .../packaging/mp1/Mp1JlinkTestIT.java | 33 +++ .../packaging/mp1/Mp1NativeTestIT.java | 33 +++ .../packaging/mp1/Mp1PackagingTestIT.java | 45 ++++ .../mp-1/web/resource.txt | 0 tests/integration/packaging/mp-2/README.md | 31 +++ .../{native-image => packaging}/mp-2/pom.xml | 131 +++++++++- .../packaging}/mp2/GreetingEntity.java | 12 +- .../packaging}/mp2/JaxRsResource.java | 4 +- .../integration/packaging}/mp2/Mp2Main.java | 5 +- .../packaging/mp2}/package-info.java | 6 +- .../src/main/resources/META-INF/beans.xml | 0 .../META-INF/microprofile-config.properties | 8 +- .../native-image.properties | 2 +- .../main/resources/META-INF/persistence.xml | 5 +- .../src/main/resources/logging.properties | 4 +- .../packaging/mp2/Mp2JarClassPathTestIT.java | 33 +++ .../packaging/mp2/Mp2JlinkTestIT.java | 33 +++ .../packaging/mp2/Mp2NativeTestIT.java | 33 +++ .../packaging/mp2/Mp2PackagingTestIT.java | 73 ++++++ .../mp-2/src/test/resources}/init.sql | 2 + tests/integration/packaging/mp-3/README.md | 8 + tests/integration/packaging/mp-3/pom.xml | 196 +++++++++++++++ .../packaging}/mp3/GreetResource.java | 4 +- .../packaging}/mp3/GreetingProvider.java | 4 +- .../integration/packaging}/mp3/Mp3Main.java | 5 +- .../packaging}/mp3/RoutingService.java | 4 +- .../packaging}/mp3/package-info.java | 4 +- .../mp-3/src/main/java/module-info.java | 10 +- .../src/main/resources/META-INF/beans.xml | 0 .../microprofile-config-test.properties | 2 +- .../META-INF/microprofile-config.properties | 2 +- .../native-image.properties | 17 ++ .../src/main/resources/logging.properties | 0 .../packaging/mp3/Mp3JarClassPathTestIT.java | 38 +++ .../packaging/mp3/Mp3JarModulePathTestIT.java | 38 +++ .../mp3/Mp3JlinkModulePathTestIT.java | 38 +++ .../packaging/mp3/Mp3JlinkTestIT.java | 38 +++ .../packaging/mp3/Mp3NativeTestIT.java | 38 +++ .../packaging/mp3/Mp3PackagingTestIT.java | 64 +++++ .../{native-image => packaging}/pom.xml | 8 +- tests/integration/packaging/se-1/README.md | 8 + .../se-1/conf/overrides.yaml | 2 +- tests/integration/packaging/se-1/pom.xml | 234 ++++++++++++++++++ .../integration/packaging}/se1/Animal.java | 4 +- .../packaging}/se1/GreetService.java | 21 +- .../packaging}/se1/MockZipkinService.java | 52 ++-- .../integration/packaging}/se1/Se1Main.java | 30 ++- .../packaging}/se1/WebClientService.java | 8 +- .../packaging}/se1/WebSocketEndpoint.java | 4 +- .../resource-config.json | 0 .../se-1/src/main/resources/application.yaml | 6 +- .../src/main/resources/logging.properties | 0 .../se-1/src/main/resources/web/resource.txt | 0 .../packaging/se1/Se1JarClassPathTestIT.java | 38 +++ .../packaging/se1/Se1JlinkTestIT.java | 38 +++ .../packaging/se1/Se1NativeTestIT.java | 38 +++ .../packaging/se1/Se1PackagingTestIT.java | 65 +++++ .../se-1/web/resource.txt | 0 .../static-content/pom.xml | 11 +- .../packaging}/staticcontent/Dummy.java | 4 +- .../src/main/resources/web-jar/resource.txt | 0 tests/integration/pom.xml | 9 +- 113 files changed, 1955 insertions(+), 886 deletions(-) delete mode 100755 etc/scripts/test-packaging-jar.sh delete mode 100755 etc/scripts/test-packaging-jlink.sh delete mode 100755 etc/scripts/test-packaging-native.sh delete mode 100644 tests/integration/native-image/mp-1/README.md delete mode 100644 tests/integration/native-image/mp-1/pom.xml delete mode 100644 tests/integration/native-image/mp-1/src/main/resources/META-INF/native-image/io.helidon.tests.integration.native-image/helidon-tests-native-image-mp-1/native-image.properties delete mode 100644 tests/integration/native-image/mp-2/README.md delete mode 100644 tests/integration/native-image/mp-3/README.md delete mode 100644 tests/integration/native-image/mp-3/pom.xml delete mode 100644 tests/integration/native-image/se-1/pom.xml create mode 100644 tests/integration/packaging/mp-1/README.md rename tests/integration/{native-image => packaging}/mp-1/logging.properties (96%) rename tests/integration/{native-image => packaging}/mp-1/mp-config-test.yaml (92%) rename tests/integration/{native-image => packaging}/mp-1/mp-config.yaml (96%) create mode 100644 tests/integration/packaging/mp-1/pom.xml rename tests/integration/{native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging}/mp1/AutoFilter.java (90%) rename tests/integration/{native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging}/mp1/BasicAuthApplication.java (90%) rename tests/integration/{native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging}/mp1/BeanClass.java (92%) rename tests/integration/{native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging}/mp1/BeanProducer.java (82%) rename tests/integration/{native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging}/mp1/JaxRsApplicationCdi.java (90%) rename tests/integration/{native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging}/mp1/JaxRsApplicationNoCdi.java (89%) rename tests/integration/{native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging}/mp1/JaxRsApplicationNoClasses.java (89%) rename tests/integration/{native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging}/mp1/JaxRsProtectedResource.java (91%) rename tests/integration/{native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging}/mp1/JaxRsResource.java (97%) rename tests/integration/{native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging}/mp1/JwtAuthApplication.java (90%) rename tests/integration/{native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging}/mp1/LivenessHealthcheck.java (92%) rename tests/integration/{native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging}/mp1/Mp1Main.java (99%) rename tests/integration/{native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging}/mp1/OidcApplication.java (90%) rename tests/integration/{native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging}/mp1/ReadinessHealthcheck.java (92%) rename tests/integration/{native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging}/mp1/RestClientIface.java (93%) rename tests/integration/{native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging}/mp1/TestBean.java (94%) rename tests/integration/{native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging}/mp1/TestDto.java (91%) rename tests/integration/{native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging}/mp1/other/BeanProcessor.java (90%) rename tests/integration/{native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging}/mp1/other/ProducedBean.java (92%) rename tests/integration/{native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging}/mp1/other/package-info.java (85%) rename tests/integration/{native-image/mp-2/src/main/java/io/helidon/tests/integration/nativeimage/mp2 => packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1}/package-info.java (77%) rename tests/integration/{native-image => packaging}/mp-1/src/main/java/module-info.java (79%) rename tests/integration/{native-image => packaging}/mp-1/src/main/resources/META-INF/beans.xml (100%) rename tests/integration/{native-image => packaging}/mp-1/src/main/resources/META-INF/microprofile-config-test.properties (91%) rename tests/integration/{native-image => packaging}/mp-1/src/main/resources/META-INF/microprofile-config.properties (89%) rename tests/integration/{native-image/mp-3/src/main/resources/META-INF/native-image/io.helidon.tests.integration.native-image/helidon-tests-native-image-mp-3 => packaging/mp-1/src/main/resources/META-INF/native-image/io.helidon.tests.integration.packaging/helidon-tests-integration-packaging-mp1}/native-image.properties (88%) rename tests/integration/{native-image => packaging}/mp-1/src/main/resources/logging.properties (95%) rename tests/integration/{native-image => packaging}/mp-1/src/main/resources/mp-meta-config.yaml (91%) rename tests/integration/{native-image => packaging}/mp-1/src/main/resources/sign-jwk.json (100%) rename tests/integration/{native-image => packaging}/mp-1/src/main/resources/verify-jwk.json (100%) rename tests/integration/{native-image => packaging}/mp-1/src/main/resources/web/resource.txt (100%) rename tests/integration/{native-image => packaging}/mp-1/src/main/resources/web/welcome.txt (100%) create mode 100644 tests/integration/packaging/mp-1/src/test/java/io/helidon/tests/integration/packaging/mp1/Mp1JarClassPathTestIT.java create mode 100644 tests/integration/packaging/mp-1/src/test/java/io/helidon/tests/integration/packaging/mp1/Mp1JarModulePathTestIT.java create mode 100644 tests/integration/packaging/mp-1/src/test/java/io/helidon/tests/integration/packaging/mp1/Mp1JlinkModulePathTestIT.java create mode 100644 tests/integration/packaging/mp-1/src/test/java/io/helidon/tests/integration/packaging/mp1/Mp1JlinkTestIT.java create mode 100644 tests/integration/packaging/mp-1/src/test/java/io/helidon/tests/integration/packaging/mp1/Mp1NativeTestIT.java create mode 100644 tests/integration/packaging/mp-1/src/test/java/io/helidon/tests/integration/packaging/mp1/Mp1PackagingTestIT.java rename tests/integration/{native-image => packaging}/mp-1/web/resource.txt (100%) create mode 100644 tests/integration/packaging/mp-2/README.md rename tests/integration/{native-image => packaging}/mp-2/pom.xml (54%) rename tests/integration/{native-image/mp-2/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-2/src/main/java/io/helidon/tests/integration/packaging}/mp2/GreetingEntity.java (86%) rename tests/integration/{native-image/mp-2/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-2/src/main/java/io/helidon/tests/integration/packaging}/mp2/JaxRsResource.java (96%) rename tests/integration/{native-image/mp-2/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-2/src/main/java/io/helidon/tests/integration/packaging}/mp2/Mp2Main.java (96%) rename tests/integration/{native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1 => packaging/mp-2/src/main/java/io/helidon/tests/integration/packaging/mp2}/package-info.java (76%) rename tests/integration/{native-image => packaging}/mp-2/src/main/resources/META-INF/beans.xml (100%) rename tests/integration/{native-image => packaging}/mp-2/src/main/resources/META-INF/microprofile-config.properties (68%) rename tests/integration/{native-image/mp-2/src/main/resources/META-INF/native-image/io.helidon.tests.integration.native-image/helidon-tests-native-image-mp-2 => packaging/mp-2/src/main/resources/META-INF/native-image/io.helidon.tests.integration.packaging/helidon-tests-integration-packaging-mp2}/native-image.properties (88%) rename tests/integration/{native-image => packaging}/mp-2/src/main/resources/META-INF/persistence.xml (87%) rename tests/integration/{native-image => packaging}/mp-2/src/main/resources/logging.properties (94%) create mode 100644 tests/integration/packaging/mp-2/src/test/java/io/helidon/tests/integration/packaging/mp2/Mp2JarClassPathTestIT.java create mode 100644 tests/integration/packaging/mp-2/src/test/java/io/helidon/tests/integration/packaging/mp2/Mp2JlinkTestIT.java create mode 100644 tests/integration/packaging/mp-2/src/test/java/io/helidon/tests/integration/packaging/mp2/Mp2NativeTestIT.java create mode 100644 tests/integration/packaging/mp-2/src/test/java/io/helidon/tests/integration/packaging/mp2/Mp2PackagingTestIT.java rename tests/integration/{native-image/mp-2 => packaging/mp-2/src/test/resources}/init.sql (67%) create mode 100644 tests/integration/packaging/mp-3/README.md create mode 100644 tests/integration/packaging/mp-3/pom.xml rename tests/integration/{native-image/mp-3/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-3/src/main/java/io/helidon/tests/integration/packaging}/mp3/GreetResource.java (97%) rename tests/integration/{native-image/mp-3/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-3/src/main/java/io/helidon/tests/integration/packaging}/mp3/GreetingProvider.java (92%) rename tests/integration/{native-image/mp-3/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-3/src/main/java/io/helidon/tests/integration/packaging}/mp3/Mp3Main.java (89%) rename tests/integration/{native-image/mp-3/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-3/src/main/java/io/helidon/tests/integration/packaging}/mp3/RoutingService.java (92%) rename tests/integration/{native-image/mp-3/src/main/java/io/helidon/tests/integration/nativeimage => packaging/mp-3/src/main/java/io/helidon/tests/integration/packaging}/mp3/package-info.java (84%) rename tests/integration/{native-image => packaging}/mp-3/src/main/java/module-info.java (68%) rename tests/integration/{native-image => packaging}/mp-3/src/main/resources/META-INF/beans.xml (100%) rename tests/integration/{native-image => packaging}/mp-3/src/main/resources/META-INF/microprofile-config-test.properties (90%) rename tests/integration/{native-image => packaging}/mp-3/src/main/resources/META-INF/microprofile-config.properties (92%) create mode 100644 tests/integration/packaging/mp-3/src/main/resources/META-INF/native-image/io.helidon.tests.integration.packaging/helidon-tests-integration-packaging-mp-3/native-image.properties rename tests/integration/{native-image => packaging}/mp-3/src/main/resources/logging.properties (100%) create mode 100644 tests/integration/packaging/mp-3/src/test/java/io/helidon/tests/integration/packaging/mp3/Mp3JarClassPathTestIT.java create mode 100644 tests/integration/packaging/mp-3/src/test/java/io/helidon/tests/integration/packaging/mp3/Mp3JarModulePathTestIT.java create mode 100644 tests/integration/packaging/mp-3/src/test/java/io/helidon/tests/integration/packaging/mp3/Mp3JlinkModulePathTestIT.java create mode 100644 tests/integration/packaging/mp-3/src/test/java/io/helidon/tests/integration/packaging/mp3/Mp3JlinkTestIT.java create mode 100644 tests/integration/packaging/mp-3/src/test/java/io/helidon/tests/integration/packaging/mp3/Mp3NativeTestIT.java create mode 100644 tests/integration/packaging/mp-3/src/test/java/io/helidon/tests/integration/packaging/mp3/Mp3PackagingTestIT.java rename tests/integration/{native-image => packaging}/pom.xml (84%) create mode 100644 tests/integration/packaging/se-1/README.md rename tests/integration/{native-image => packaging}/se-1/conf/overrides.yaml (91%) create mode 100644 tests/integration/packaging/se-1/pom.xml rename tests/integration/{native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage => packaging/se-1/src/main/java/io/helidon/tests/integration/packaging}/se1/Animal.java (91%) rename tests/integration/{native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage => packaging/se-1/src/main/java/io/helidon/tests/integration/packaging}/se1/GreetService.java (85%) rename tests/integration/{native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage => packaging/se-1/src/main/java/io/helidon/tests/integration/packaging}/se1/MockZipkinService.java (51%) rename tests/integration/{native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage => packaging/se-1/src/main/java/io/helidon/tests/integration/packaging}/se1/Se1Main.java (81%) rename tests/integration/{native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage => packaging/se-1/src/main/java/io/helidon/tests/integration/packaging}/se1/WebClientService.java (94%) rename tests/integration/{native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage => packaging/se-1/src/main/java/io/helidon/tests/integration/packaging}/se1/WebSocketEndpoint.java (92%) rename tests/integration/{native-image/se-1/src/main/resources/META-INF/native-image/io.helidon.tests.integration.native-image/helidon-tests-native-image-se-1 => packaging/se-1/src/main/resources/META-INF/native-image/io.helidon.tests.integration.packaging/helidon-tests-integration-packaging-se-1}/resource-config.json (100%) rename tests/integration/{native-image => packaging}/se-1/src/main/resources/application.yaml (89%) rename tests/integration/{native-image => packaging}/se-1/src/main/resources/logging.properties (100%) rename tests/integration/{native-image => packaging}/se-1/src/main/resources/web/resource.txt (100%) create mode 100644 tests/integration/packaging/se-1/src/test/java/io/helidon/tests/integration/packaging/se1/Se1JarClassPathTestIT.java create mode 100644 tests/integration/packaging/se-1/src/test/java/io/helidon/tests/integration/packaging/se1/Se1JlinkTestIT.java create mode 100644 tests/integration/packaging/se-1/src/test/java/io/helidon/tests/integration/packaging/se1/Se1NativeTestIT.java create mode 100644 tests/integration/packaging/se-1/src/test/java/io/helidon/tests/integration/packaging/se1/Se1PackagingTestIT.java rename tests/integration/{native-image => packaging}/se-1/web/resource.txt (100%) rename tests/integration/{native-image => packaging}/static-content/pom.xml (75%) rename tests/integration/{native-image/static-content/src/main/java/io/helidon/tests/integration/nativeimage => packaging/static-content/src/main/java/io/helidon/tests/integration/packaging}/staticcontent/Dummy.java (84%) rename tests/integration/{native-image => packaging}/static-content/src/main/resources/web-jar/resource.txt (100%) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 2d0e0449e29..fbb9be5b363 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -134,7 +134,7 @@ jobs: cache: maven - uses: graalvm/setup-graalvm@v1 with: - java-version: 21 + java-version: '21' distribution: graalvm-community github-token: ${{ secrets.GITHUB_TOKEN }} native-image-job-reports: true @@ -211,31 +211,92 @@ jobs: -f archetypes/pom.xml \ install packaging: - timeout-minutes: 60 + timeout-minutes: 30 + strategy: + matrix: + os: [ ubuntu-20.04, macos-14 ] + packaging: [ jar, jlink ] + include: + - { os: ubuntu-20.04, platform: linux } + - { os: macos-14, platform: macos } + runs-on: ${{ matrix.os }} + name: tests/packaging-${{ matrix.packaging }}-${{ matrix.platform }} + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref }} + - name: Set up JDK ${{ env.JAVA_VERSION }} + uses: actions/setup-java@v4.1.0 + with: + distribution: ${{ env.JAVA_DISTRO }} + java-version: ${{ env.JAVA_VERSION }} + cache: maven + - name: Free Space + shell: bash + run: | + # See https://github.com/actions/runner-images/issues/2840 + sudo rm -rf /usr/share/dotnet + sudo rm -rf /usr/local/share/powershell + - name: Build Helidon + run: | + # prime build + mvn ${MAVEN_ARGS} -e \ + -DskipTests \ + -Ptests \ + install + - name: Run Test + run: | + mvn ${MAVEN_ARGS} \ + -f tests/integration/packaging/pom.xml \ + -P${{ matrix.packaging }}-image \ + verify + native-image: + timeout-minutes: 30 strategy: matrix: - os: [ ubuntu-20.04, macos-14] + os: [ ubuntu-20.04, macos-14 ] + module: [ mp-1, mp-2, mp-3, se-1 ] + include: + - { os: ubuntu-20.04, platform: linux } + - { os: macos-14, platform: macos } runs-on: ${{ matrix.os }} + name: tests/native-image-${{ matrix.module }}-${{ matrix.platform }} steps: - uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref }} - uses: graalvm/setup-graalvm@v1 with: - java-version: 21 + java-version: ${{ env.JAVA_VERSION }} distribution: graalvm-community github-token: ${{ secrets.GITHUB_TOKEN }} native-image-job-reports: true cache: maven + - name: Free Space + shell: bash + run: | + # See https://github.com/actions/runner-images/issues/2840 + sudo rm -rf /usr/share/dotnet + sudo rm -rf /usr/local/share/powershell - name: Build Helidon run: | # prime build mvn ${MAVEN_ARGS} -e \ - -Dmaven.test.skip=true \ -DskipTests \ - -Ppipeline \ + -Ptests \ install - - name: JAR packaging - run: etc/scripts/test-packaging-jar.sh - - name: JLink packaging - run: etc/scripts/test-packaging-jlink.sh - - name: Native-Image packaging - run: etc/scripts/test-packaging-native.sh + - name: Run Test + run: | + mvn ${MAVEN_ARGS} -e \ + -f tests/integration/packaging/pom.xml \ + -pl ${{ matrix.module }} \ + -Pnative-image \ + -am \ + verify + gate: + runs-on: ubuntu-20.04 + needs: [ copyright, checkstyle, shellcheck, build, docs, spotbugs, packaging, native-image, archetypes, mp-tck ] + steps: + - shell: bash + run: | + echo OK diff --git a/etc/scripts/test-packaging-jar.sh b/etc/scripts/test-packaging-jar.sh deleted file mode 100755 index e3deeebfb5f..00000000000 --- a/etc/scripts/test-packaging-jar.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2021, 2024 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. -# - -set -o pipefail || true # trace ERR through pipes -set -o errtrace || true # trace ERR through commands and functions -set -o errexit || true # exit the script if any statement returns a non-true return value - -on_error(){ - CODE="${?}" && \ - set +x && \ - printf "[ERROR] Error(code=%s) occurred at %s:%s command: %s\n" \ - "${CODE}" "${BASH_SOURCE[0]}" "${LINENO}" "${BASH_COMMAND}" -} -trap on_error ERR - -# Path to this script -if [ -h "${0}" ] ; then - SCRIPT_PATH="$(readlink "${0}")" -else - # shellcheck disable=SC155 - SCRIPT_PATH="${0}" -fi -readonly SCRIPT_PATH - -# Path to the root of the workspace -# shellcheck disable=SC2046 -WS_DIR=$(cd $(dirname -- "${SCRIPT_PATH}") ; cd ../.. ; pwd -P) -readonly WS_DIR - -# Run native image tests -cd "${WS_DIR}/tests/integration/native-image" - -# Prime build all native-image tests -# shellcheck disable=SC2086 -mvn ${MAVEN_ARGS} -e clean install - -# Run tests with classpath and then module path - -# -# Run MP-1 -# -cd "${WS_DIR}/tests/integration/native-image/mp-1" -# Classpath -java -jar target/helidon-tests-native-image-mp-1.jar - -# Module Path -java --module-path target/helidon-tests-native-image-mp-1.jar:target/libs \ - --module helidon.tests.nimage.mp - -# -# Run MP-3 (just start and stop) -# -cd "${WS_DIR}/tests/integration/native-image/mp-3" -# Classpath -java -Dexit.on.started=! -jar target/helidon-tests-native-image-mp-3.jar - -# Module Path -java -Dexit.on.started=! \ - --module-path target/helidon-tests-native-image-mp-3.jar:target/libs \ - --add-modules helidon.tests.nimage.quickstartmp \ - --module io.helidon.microprofile.cdi/io.helidon.microprofile.cdi.Main diff --git a/etc/scripts/test-packaging-jlink.sh b/etc/scripts/test-packaging-jlink.sh deleted file mode 100755 index 3675332168e..00000000000 --- a/etc/scripts/test-packaging-jlink.sh +++ /dev/null @@ -1,85 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2021, 2024 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. -# - -set -o pipefail || true # trace ERR through pipes -set -o errtrace || true # trace ERR through commands and functions -set -o errexit || true # exit the script if any statement returns a non-true return value - -on_error(){ - CODE="${?}" && \ - set +x && \ - printf "[ERROR] Error(code=%s) occurred at %s:%s command: %s\n" \ - "${CODE}" "${BASH_SOURCE[0]}" "${LINENO}" "${BASH_COMMAND}" -} -trap on_error ERR - -# Path to this script -if [ -h "${0}" ] ; then - SCRIPT_PATH="$(readlink "${0}")" -else - # shellcheck disable=SC155 - SCRIPT_PATH="${0}" -fi -readonly SCRIPT_PATH - -# Path to the root of the workspace -# shellcheck disable=SC2046 -WS_DIR=$(cd $(dirname -- "${SCRIPT_PATH}") ; cd ../.. ; pwd -P) -readonly WS_DIR - -# Run native image tests -cd "${WS_DIR}/tests/integration/native-image" - -# Prime build all native-image tests -# shellcheck disable=SC2086 -mvn ${MAVEN_ARGS} -e clean install - -# Build jlink images -# mp-2 fails because of https://github.com/oracle/helidon-build-tools/issues/478 -readonly native_image_tests="mp-1 mp-3" -for native_test in ${native_image_tests}; do - cd "${WS_DIR}/tests/integration/native-image/${native_test}" - # shellcheck disable=SC2086 - mvn ${MAVEN_ARGS} package -e -Pjlink-image,staging -Djlink.image.addClassDataSharingArchive=false -Djlink.image.testImage=false -done - -# Run tests with classpath and then module path - -# Run MP-1 -cd "${WS_DIR}/tests/integration/native-image/mp-1" -jri_dir="${WS_DIR}/tests/integration/native-image/mp-1/target/helidon-tests-native-image-mp-1-jri" - -# Classpath -"${jri_dir}"/bin/start - -# Module Path -"${jri_dir}"/bin/java \ - --module-path "${jri_dir}/app/helidon-tests-native-image-mp-1.jar:${jri_dir}/app/libs" \ - --module helidon.tests.nimage.mp - -# Run MP-3 (just start and stop) -cd "${WS_DIR}/tests/integration/native-image/mp-3" -jri_dir=${WS_DIR}/tests/integration/native-image/mp-3/target/helidon-tests-native-image-mp-3-jri - -# Classpath -"${jri_dir}"/bin/start --test - -# Module Path -"${jri_dir}"/bin/java -Dexit.on.started=! \ - --module-path "${jri_dir}/app/helidon-tests-native-image-mp-3.jar:${jri_dir}/app/libs" \ - --add-modules helidon.tests.nimage.quickstartmp \ - --module io.helidon.microprofile.cdi/io.helidon.microprofile.cdi.Main diff --git a/etc/scripts/test-packaging-native.sh b/etc/scripts/test-packaging-native.sh deleted file mode 100755 index e5b5da63f33..00000000000 --- a/etc/scripts/test-packaging-native.sh +++ /dev/null @@ -1,82 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2021, 2024 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. -# - -set -o pipefail || true # trace ERR through pipes -set -o errtrace || true # trace ERR through commands and functions -set -o errexit || true # exit the script if any statement returns a non-true return value - -on_error(){ - CODE="${?}" && \ - set +x && \ - printf "[ERROR] Error(code=%s) occurred at %s:%s command: %s\n" \ - "${CODE}" "${BASH_SOURCE[0]}" "${LINENO}" "${BASH_COMMAND}" -} -trap on_error ERR - -# Path to this script -if [ -h "${0}" ] ; then - SCRIPT_PATH="$(readlink "${0}")" -else - # shellcheck disable=SC155 - SCRIPT_PATH="${0}" -fi -readonly SCRIPT_PATH - -# Path to the root of the workspace -# shellcheck disable=SC2046 -WS_DIR=$(cd $(dirname -- "${SCRIPT_PATH}") ; cd ../.. ; pwd -P) -readonly WS_DIR - -if [ -z "${GRAALVM_HOME}" ]; then - echo "ERROR: GRAALVM_HOME is not set"; - exit 1 -fi - -if [ ! -x "${GRAALVM_HOME}/bin/native-image" ]; then - echo "ERROR: ${GRAALVM_HOME}/bin/native-image does not exist or is not executable"; - exit 1 -fi - -# shellcheck disable=SC2086 -mvn ${MAVEN_ARGS} --version - -echo "GRAALVM_HOME=${GRAALVM_HOME}"; -"${GRAALVM_HOME}"/bin/native-image --version; - -# Run native image tests -cd "${WS_DIR}/tests/integration/native-image" - -# Prime build all native-image tests -# shellcheck disable=SC2086 -mvn ${MAVEN_ARGS} -e clean install - -# Build native images -readonly native_image_tests="se-1 mp-1 mp-3" -for native_test in ${native_image_tests}; do - cd "${WS_DIR}/tests/integration/native-image/${native_test}" - # shellcheck disable=SC2086 - mvn ${MAVEN_ARGS} -e clean package -Pnative-image -done - -# Run this one because it has no pre-reqs and self-tests -# Uses relative path to read configuration -cd "${WS_DIR}/tests/integration/native-image/mp-1" -./target/helidon-tests-native-image-mp-1 || true - -# Run se-1 exiting on started -cd "${WS_DIR}/tests/integration/native-image/se-1" -./target/helidon-tests-native-image-se-1 -Dexit.on.started=! || true diff --git a/tests/integration/native-image/mp-1/README.md b/tests/integration/native-image/mp-1/README.md deleted file mode 100644 index 88293667f3d..00000000000 --- a/tests/integration/native-image/mp-1/README.md +++ /dev/null @@ -1,40 +0,0 @@ -#GraalVM native image integration test -_____ - -This is a manual (for the time being) test of integration with native-image. - -To run this test: - -```shell script -mvn clean package -Dnative.image=$path_to_native_image -./target/native-image -``` - -There are a tests run from within the application. -Tests: -1. Injection of Config - - -To run using module-path: -```shell script -java --module-path target/libs:target/helidon-tests-native-image-mp-1.jar -m helidon.tests.nimage.mp/io.helidon.tests.integration.nativeimage.mp1.Mp1Main -``` - -To build native image using Helidon feature tracing (with maven): -Add a file `META-INF/native-image/native-image.properties` with the following content: - -```properties -Args=-Dhelidon.native.reflection.trace=true -Dhelidon.native.reflection.trace-parsing=true -``` - -To build native image using Helidon feature tracing (without maven): -```shell script -${GRAALVM_HOME}/bin/native-image -Dhelidon.native.reflection.trace-parsing=true \ - -Dhelidon.native.reflection.trace=true \ - -H:Path=./target \ - -H:Name=helidon-tests-native-image-mp-1 \ - -H:+ReportExceptionStackTraces \ - -jar ./target/helidon-tests-native-image-mp-1.jar -``` - - \ No newline at end of file diff --git a/tests/integration/native-image/mp-1/pom.xml b/tests/integration/native-image/mp-1/pom.xml deleted file mode 100644 index c1405fe9ff4..00000000000 --- a/tests/integration/native-image/mp-1/pom.xml +++ /dev/null @@ -1,117 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../../applications/mp/pom.xml - - io.helidon.tests.integration.native-image - helidon-tests-native-image-mp-1 - Helidon Tests Integration GraalVM Native image MP1 - - - This test makes sure the following helidon modules can be compiled into native image: - Microprofile CDI - Microprofile - Server - Microprofile Tracing - Jaeger Tracer - Microprofile Access Log - Microprofile Fault Tolerance - Microprofile - Metrics - Microprofile Health Check - Microprofile Rest Client - Microprofile Config - YAML configuration - JSON-P - - JSON-B - Microprofile JWT-Auth - - - - io.helidon.tests.integration.nativeimage.mp1.Mp1Main - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - helidon-microprofile-tracing - io.helidon.microprofile.tracing - - - io.helidon.security.providers - helidon-security-providers-oidc - - - io.helidon.tracing.providers - helidon-tracing-providers-jaeger - runtime - - - io.helidon.microprofile - helidon-microprofile-access-log - runtime - - - io.helidon.metrics - helidon-metrics - runtime - - - io.smallrye - jandex - runtime - - - org.junit.jupiter - junit-jupiter-api - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - org.graalvm.buildtools - native-maven-plugin - - - build-native-image - - true - - - - - - - diff --git a/tests/integration/native-image/mp-1/src/main/resources/META-INF/native-image/io.helidon.tests.integration.native-image/helidon-tests-native-image-mp-1/native-image.properties b/tests/integration/native-image/mp-1/src/main/resources/META-INF/native-image/io.helidon.tests.integration.native-image/helidon-tests-native-image-mp-1/native-image.properties deleted file mode 100644 index f53634fa17d..00000000000 --- a/tests/integration/native-image/mp-1/src/main/resources/META-INF/native-image/io.helidon.tests.integration.native-image/helidon-tests-native-image-mp-1/native-image.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2023, 2024 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. -# - -Args=--initialize-at-build-time=io.helidon.tests.integration.nativeimage.mp1 \ - --initialize-at-build-time=io.helidon.common.features \ - --initialize-at-build-time=io.helidon.jersey.client.JerseyClientBuilderListener \ - --initialize-at-build-time=io.helidon.logging.jul.JulMdcPropagator diff --git a/tests/integration/native-image/mp-2/README.md b/tests/integration/native-image/mp-2/README.md deleted file mode 100644 index 2ca98b112ad..00000000000 --- a/tests/integration/native-image/mp-2/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# GraalVM native image integration test MP-2 -_____ - -## Build - -```shell -mvn clean package -Pnative-image -``` - -## Run - -Start the database: -```shell -docker run -it --rm \ - -name oracledb \ - -e ORACLE_PWD=oracle \ - -v $PWD/init.sql:/opt/oracle/scripts/startup/init.sql \ - -p 1521:1521 \ - container-registry.oracle.com/database/express:latest -``` - -Run the application: -```shell -./target/helidon-tests-native-image-mp-2 -``` diff --git a/tests/integration/native-image/mp-3/README.md b/tests/integration/native-image/mp-3/README.md deleted file mode 100644 index 7ec45a652f1..00000000000 --- a/tests/integration/native-image/mp-3/README.md +++ /dev/null @@ -1,21 +0,0 @@ -#GraalVM native image integration test MP-3 -_____ - -This is a manual (for the time being) test of integration with native-image. - -To run this test: - -```shell script -export GRAALVM_HOME=${path.to.graal.with.native-image} -mvn clean package -Pnative-image -./target/helidon-tests-native-image-mp-3 -``` - -Requires at least GraalVM 20.0.0 - -This test validates that Quickstart can run on native image with minimal number of changes - eventually with no changes. - -To run this test using module path: -```shell script -java --module-path target/libs:target/helidon-tests-native-image-mp-3.jar --add-modules helidon.tests.nimage.quickstartmp -m io.helidon.microprofile.cdi/io.helidon.microprofile.cdi.Main -``` diff --git a/tests/integration/native-image/mp-3/pom.xml b/tests/integration/native-image/mp-3/pom.xml deleted file mode 100644 index 597c24f49e0..00000000000 --- a/tests/integration/native-image/mp-3/pom.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-mp - 4.1.0-SNAPSHOT - ../../../../applications/mp/pom.xml - - io.helidon.tests.integration.native-image - helidon-tests-native-image-mp-3 - Helidon Tests Integration GraalVM Native image MP3 - - - This test uses quickstart application with minimal number of changes - - - - io.helidon.tests.integration.nativeimage.mp3.Mp3Main - - - - - io.helidon.microprofile.bundles - helidon-microprofile - - - io.smallrye - jandex - runtime - true - - - org.junit.jupiter - junit-jupiter-api - test - - - - - - - org.graalvm.buildtools - native-maven-plugin - - true - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - io.smallrye - jandex-maven-plugin - - - make-index - - - - - - diff --git a/tests/integration/native-image/se-1/pom.xml b/tests/integration/native-image/se-1/pom.xml deleted file mode 100644 index 63293350462..00000000000 --- a/tests/integration/native-image/se-1/pom.xml +++ /dev/null @@ -1,119 +0,0 @@ - - - - - 4.0.0 - - io.helidon.applications - helidon-se - 4.1.0-SNAPSHOT - ../../../../applications/se/pom.xml - - io.helidon.tests.integration.native-image - helidon-tests-native-image-se-1 - Helidon Tests Integration GraalVM Native image SE 1 - - - io.helidon.tests.integration.nativeimage.se1.Se1Main - - - - - io.helidon.webserver - helidon-webserver - - - io.helidon.webserver - helidon-webserver-static-content - - - io.helidon.webserver - helidon-webserver-websocket - - - io.helidon.http.media - helidon-http-media-jsonp - - - io.helidon.http.media - helidon-http-media-jsonb - - - io.helidon.config - helidon-config-yaml - - - io.helidon.tracing - helidon-tracing - - - io.helidon.tracing.providers - helidon-tracing-providers-zipkin - - - io.helidon.webserver.observe - helidon-webserver-observe-health - - - io.helidon.webclient - helidon-webclient - - - helidon-webclient-tracing - io.helidon.webclient - - - io.helidon.common - helidon-common-reactive - - - io.helidon.logging - helidon-logging-common - - - io.helidon.tests.integration - helidon-tests-native-image-static-content - ${project.version} - - - io.helidon.logging - helidon-logging-jul - runtime - - - org.junit.jupiter - junit-jupiter-api - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-libs - - - - - - diff --git a/tests/integration/packaging/mp-1/README.md b/tests/integration/packaging/mp-1/README.md new file mode 100644 index 00000000000..cad0c5da6a0 --- /dev/null +++ b/tests/integration/packaging/mp-1/README.md @@ -0,0 +1,44 @@ +# Packaging Integration Test MP1 + +This test makes sure the following helidon modules can be compiled into native image: +- Microprofile CDI +- Microprofile Server +- Microprofile Tracing +- Jaeger Tracer +- Microprofile Access Log +- Microprofile Fault Tolerance +- Microprofile Metrics +- Microprofile Health Check +- Microprofile Rest Client +- Microprofile Config +- YAML configuration +- JSON-P +- JSON-B +- Microprofile JWT-Auth + +To run this test: +```shell +mvn clean verify +mvn clean verify -Pnative-image +mvn clean verify -Pjlink-image +``` + +--- + +To build native image using Helidon feature tracing (with maven): +Add a file `META-INF/native-image/native-image.properties` with the following content: + +```properties +Args=-Dhelidon.native.reflection.trace=true -Dhelidon.native.reflection.trace-parsing=true +``` + +To build native image using Helidon feature tracing (without maven): +```shell +native-image \ + -Dhelidon.native.reflection.trace-parsing=true \ + -Dhelidon.native.reflection.trace=true \ + -H:Path=./target \ + -H:Name=helidon-tests-packaging-mp-1 \ + -H:+ReportExceptionStackTraces \ + -jar ./target/helidon-tests-packaging-mp-1.jar +``` diff --git a/tests/integration/native-image/mp-1/logging.properties b/tests/integration/packaging/mp-1/logging.properties similarity index 96% rename from tests/integration/native-image/mp-1/logging.properties rename to tests/integration/packaging/mp-1/logging.properties index bf0c057c7fe..adb0aebdc26 100644 --- a/tests/integration/native-image/mp-1/logging.properties +++ b/tests/integration/packaging/mp-1/logging.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2018, 2023 Oracle and/or its affiliates. +# Copyright (c) 2018, 2024 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. diff --git a/tests/integration/native-image/mp-1/mp-config-test.yaml b/tests/integration/packaging/mp-1/mp-config-test.yaml similarity index 92% rename from tests/integration/native-image/mp-1/mp-config-test.yaml rename to tests/integration/packaging/mp-1/mp-config-test.yaml index 8edd223834c..2d19304d017 100644 --- a/tests/integration/native-image/mp-1/mp-config-test.yaml +++ b/tests/integration/packaging/mp-1/mp-config-test.yaml @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, 2021 Oracle and/or its affiliates. +# Copyright (c) 2019, 2024 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. diff --git a/tests/integration/native-image/mp-1/mp-config.yaml b/tests/integration/packaging/mp-1/mp-config.yaml similarity index 96% rename from tests/integration/native-image/mp-1/mp-config.yaml rename to tests/integration/packaging/mp-1/mp-config.yaml index 1fd77ee6890..17f8329a380 100644 --- a/tests/integration/native-image/mp-1/mp-config.yaml +++ b/tests/integration/packaging/mp-1/mp-config.yaml @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, 2023 Oracle and/or its affiliates. +# Copyright (c) 2020, 2024 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. diff --git a/tests/integration/packaging/mp-1/pom.xml b/tests/integration/packaging/mp-1/pom.xml new file mode 100644 index 00000000000..c499ce8f17b --- /dev/null +++ b/tests/integration/packaging/mp-1/pom.xml @@ -0,0 +1,227 @@ + + + + + 4.0.0 + + io.helidon.applications + helidon-mp + 4.1.0-SNAPSHOT + ../../../../applications/mp/pom.xml + + io.helidon.tests.integration.packaging + helidon-tests-integration-packaging-mp-1 + Helidon Tests Integration Packaging MP1 + + + io.helidon.tests.integration.packaging.mp1.Mp1Main + true + + + + + io.helidon.microprofile.bundles + helidon-microprofile + + + helidon-microprofile-tracing + io.helidon.microprofile.tracing + + + io.helidon.security.providers + helidon-security-providers-oidc + + + io.helidon.inject + helidon-inject-runtime + true + + + io.helidon.tracing.providers + helidon-tracing-providers-jaeger + runtime + + + io.helidon.microprofile + helidon-microprofile-access-log + runtime + + + io.helidon.metrics + helidon-metrics + runtime + + + io.smallrye + jandex + runtime + + + io.helidon.logging + helidon-logging-jul + + + org.junit.jupiter + junit-jupiter-api + test + + + org.hamcrest + hamcrest-all + test + + + io.helidon.tests.integration + helidon-tests-integration-harness + ${project.version} + test + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-libs + + + + + io.smallrye + jandex-maven-plugin + + + make-index + + + + + org.graalvm.buildtools + native-maven-plugin + + + build-native-image + + true + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + **/*IT + + + + ${project.build.outputDirectory}/logging.properties + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + ${project.build.outputDirectory}/logging.properties + + + ${redirectTestOutputToFile} + + + + + integration-test + verify + + + + + + + + + + jar-image + + true + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + **/*Jar*IT + + + + + + + + native-image + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + **/*Native*IT + + + + + + + + jlink-image + + + + io.helidon.build-tools + helidon-maven-plugin + + false + false + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + **/*Jlink*IT + + + + + + + + diff --git a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/AutoFilter.java b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/AutoFilter.java similarity index 90% rename from tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/AutoFilter.java rename to tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/AutoFilter.java index 38c01fffc73..bbae78fe82e 100644 --- a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/AutoFilter.java +++ b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/AutoFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. + * Copyright (c) 2020, 2024 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.mp1; +package io.helidon.tests.integration.packaging.mp1; import java.util.concurrent.atomic.AtomicInteger; diff --git a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/BasicAuthApplication.java b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/BasicAuthApplication.java similarity index 90% rename from tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/BasicAuthApplication.java rename to tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/BasicAuthApplication.java index 2cacdc20dd7..ab70949c310 100644 --- a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/BasicAuthApplication.java +++ b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/BasicAuthApplication.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. + * Copyright (c) 2020, 2024 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.mp1; +package io.helidon.tests.integration.packaging.mp1; import java.util.Set; diff --git a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/BeanClass.java b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/BeanClass.java similarity index 92% rename from tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/BeanClass.java rename to tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/BeanClass.java index fdad307bddf..0561ac41ac6 100644 --- a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/BeanClass.java +++ b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/BeanClass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. + * Copyright (c) 2020, 2024 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.mp1; +package io.helidon.tests.integration.packaging.mp1; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.RequestScoped; diff --git a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/BeanProducer.java b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/BeanProducer.java similarity index 82% rename from tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/BeanProducer.java rename to tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/BeanProducer.java index fa69df95f43..7c70f58d6a8 100644 --- a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/BeanProducer.java +++ b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/BeanProducer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. + * Copyright (c) 2020, 2024 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. @@ -14,12 +14,12 @@ * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.mp1; +package io.helidon.tests.integration.packaging.mp1; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.inject.Produces; -import io.helidon.tests.integration.nativeimage.mp1.other.ProducedBean; +import io.helidon.tests.integration.packaging.mp1.other.ProducedBean; @ApplicationScoped public class BeanProducer { diff --git a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/JaxRsApplicationCdi.java b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/JaxRsApplicationCdi.java similarity index 90% rename from tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/JaxRsApplicationCdi.java rename to tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/JaxRsApplicationCdi.java index acdeb65cc3e..c2676888a1c 100644 --- a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/JaxRsApplicationCdi.java +++ b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/JaxRsApplicationCdi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. + * Copyright (c) 2019, 2024 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.mp1; +package io.helidon.tests.integration.packaging.mp1; import java.util.Set; diff --git a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/JaxRsApplicationNoCdi.java b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/JaxRsApplicationNoCdi.java similarity index 89% rename from tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/JaxRsApplicationNoCdi.java rename to tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/JaxRsApplicationNoCdi.java index 4aa615393f7..c968df8d043 100644 --- a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/JaxRsApplicationNoCdi.java +++ b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/JaxRsApplicationNoCdi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. + * Copyright (c) 2019, 2024 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.mp1; +package io.helidon.tests.integration.packaging.mp1; import java.util.Set; diff --git a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/JaxRsApplicationNoClasses.java b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/JaxRsApplicationNoClasses.java similarity index 89% rename from tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/JaxRsApplicationNoClasses.java rename to tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/JaxRsApplicationNoClasses.java index d4b2d660be3..ca4e14900b1 100644 --- a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/JaxRsApplicationNoClasses.java +++ b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/JaxRsApplicationNoClasses.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. + * Copyright (c) 2020, 2024 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.mp1; +package io.helidon.tests.integration.packaging.mp1; import jakarta.enterprise.context.ApplicationScoped; import jakarta.ws.rs.ApplicationPath; diff --git a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/JaxRsProtectedResource.java b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/JaxRsProtectedResource.java similarity index 91% rename from tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/JaxRsProtectedResource.java rename to tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/JaxRsProtectedResource.java index 9859dd0f3b5..ab6e5233c27 100644 --- a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/JaxRsProtectedResource.java +++ b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/JaxRsProtectedResource.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. + * Copyright (c) 2019, 2024 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.mp1; +package io.helidon.tests.integration.packaging.mp1; import jakarta.annotation.security.PermitAll; import jakarta.annotation.security.RolesAllowed; diff --git a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/JaxRsResource.java b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/JaxRsResource.java similarity index 97% rename from tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/JaxRsResource.java rename to tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/JaxRsResource.java index 645ab9fd345..5e76dc174d3 100644 --- a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/JaxRsResource.java +++ b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/JaxRsResource.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023 Oracle and/or its affiliates. + * Copyright (c) 2019, 2024 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.mp1; +package io.helidon.tests.integration.packaging.mp1; import java.lang.System.Logger.Level; import java.lang.reflect.Field; diff --git a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/JwtAuthApplication.java b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/JwtAuthApplication.java similarity index 90% rename from tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/JwtAuthApplication.java rename to tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/JwtAuthApplication.java index c5fb927ac69..9e1e650b3e5 100644 --- a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/JwtAuthApplication.java +++ b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/JwtAuthApplication.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. + * Copyright (c) 2020, 2024 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.mp1; +package io.helidon.tests.integration.packaging.mp1; import java.util.Set; diff --git a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/LivenessHealthcheck.java b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/LivenessHealthcheck.java similarity index 92% rename from tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/LivenessHealthcheck.java rename to tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/LivenessHealthcheck.java index 1382bf4037d..e9b19649baf 100644 --- a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/LivenessHealthcheck.java +++ b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/LivenessHealthcheck.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. + * Copyright (c) 2019, 2024 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.mp1; +package io.helidon.tests.integration.packaging.mp1; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; diff --git a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/Mp1Main.java b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/Mp1Main.java similarity index 99% rename from tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/Mp1Main.java rename to tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/Mp1Main.java index 302b3caa3ed..2df25015bed 100644 --- a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/Mp1Main.java +++ b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/Mp1Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023 Oracle and/or its affiliates. + * Copyright (c) 2019, 2024 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.mp1; +package io.helidon.tests.integration.packaging.mp1; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -129,7 +129,7 @@ private static String generateJwtToken() { .addUserGroup("admin") .addScope("admin_scope") .algorithm(JwkRSA.ALG_RS256) - .issuer("native-image-mp1") + .issuer("helidon-tests-packaging-mp1") .addAudience("http://localhost:8087/jwt") .issueTime(Instant.now()) .userPrincipal("jack") @@ -564,7 +564,7 @@ private static void validateMetrics(Errors.Collector collector, WebTarget target .request(MediaType.APPLICATION_JSON) .get(JsonObject.class); - JsonObject timer = application.getJsonObject("io.helidon.tests.integration.nativeimage.mp1.TestBean.config"); + JsonObject timer = application.getJsonObject("io.helidon.tests.integration.packaging.mp1.TestBean.config"); if (null == timer) { collector.fatal("Timer for TestBean.config() is not present in metrics result"); } else { diff --git a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/OidcApplication.java b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/OidcApplication.java similarity index 90% rename from tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/OidcApplication.java rename to tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/OidcApplication.java index 9f21d644278..48100095e3d 100644 --- a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/OidcApplication.java +++ b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/OidcApplication.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. + * Copyright (c) 2020, 2024 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.mp1; +package io.helidon.tests.integration.packaging.mp1; import java.util.Set; diff --git a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/ReadinessHealthcheck.java b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/ReadinessHealthcheck.java similarity index 92% rename from tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/ReadinessHealthcheck.java rename to tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/ReadinessHealthcheck.java index 29d9830c345..c703ca082d5 100644 --- a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/ReadinessHealthcheck.java +++ b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/ReadinessHealthcheck.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. + * Copyright (c) 2020, 2024 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.mp1; +package io.helidon.tests.integration.packaging.mp1; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; diff --git a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/RestClientIface.java b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/RestClientIface.java similarity index 93% rename from tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/RestClientIface.java rename to tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/RestClientIface.java index a7e02d017d4..f23b748ec63 100644 --- a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/RestClientIface.java +++ b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/RestClientIface.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. + * Copyright (c) 2019, 2024 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.mp1; +package io.helidon.tests.integration.packaging.mp1; import jakarta.json.JsonObject; import jakarta.ws.rs.GET; diff --git a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/TestBean.java b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/TestBean.java similarity index 94% rename from tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/TestBean.java rename to tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/TestBean.java index 29c1e0a82bb..ba0f4ce1006 100644 --- a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/TestBean.java +++ b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/TestBean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023 Oracle and/or its affiliates. + * Copyright (c) 2019, 2024 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.mp1; +package io.helidon.tests.integration.packaging.mp1; import java.net.URI; import java.time.temporal.ChronoUnit; @@ -26,8 +26,8 @@ import jakarta.inject.Inject; import io.helidon.microprofile.server.ServerCdiExtension; -import io.helidon.tests.integration.nativeimage.mp1.other.BeanProcessor; -import io.helidon.tests.integration.nativeimage.mp1.other.ProducedBean; +import io.helidon.tests.integration.packaging.mp1.other.BeanProcessor; +import io.helidon.tests.integration.packaging.mp1.other.ProducedBean; import org.eclipse.microprofile.config.inject.ConfigProperty; import org.eclipse.microprofile.faulttolerance.Asynchronous; diff --git a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/TestDto.java b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/TestDto.java similarity index 91% rename from tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/TestDto.java rename to tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/TestDto.java index 5d4e231ec06..ffed7000c5c 100644 --- a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/TestDto.java +++ b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/TestDto.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. + * Copyright (c) 2019, 2024 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.mp1; +package io.helidon.tests.integration.packaging.mp1; import io.helidon.common.Reflected; diff --git a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/other/BeanProcessor.java b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/other/BeanProcessor.java similarity index 90% rename from tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/other/BeanProcessor.java rename to tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/other/BeanProcessor.java index cd669c8e4e3..2544ca0721c 100644 --- a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/other/BeanProcessor.java +++ b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/other/BeanProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022 Oracle and/or its affiliates. + * Copyright (c) 2020, 2024 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.mp1.other; +package io.helidon.tests.integration.packaging.mp1.other; public final class BeanProcessor { diff --git a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/other/ProducedBean.java b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/other/ProducedBean.java similarity index 92% rename from tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/other/ProducedBean.java rename to tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/other/ProducedBean.java index 710c60ce822..dbdd5897ad6 100644 --- a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/other/ProducedBean.java +++ b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/other/ProducedBean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Oracle and/or its affiliates. + * Copyright (c) 2020, 2024 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.mp1.other; +package io.helidon.tests.integration.packaging.mp1.other; import java.util.Objects; diff --git a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/other/package-info.java b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/other/package-info.java similarity index 85% rename from tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/other/package-info.java rename to tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/other/package-info.java index e2c09cfbd69..aec2030469c 100644 --- a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/other/package-info.java +++ b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/other/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Oracle and/or its affiliates. + * Copyright (c) 2020, 2024 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. @@ -17,4 +17,4 @@ * This package exists to make sure we can do proxies that have working * package local */ -package io.helidon.tests.integration.nativeimage.mp1.other; \ No newline at end of file +package io.helidon.tests.integration.packaging.mp1.other; \ No newline at end of file diff --git a/tests/integration/native-image/mp-2/src/main/java/io/helidon/tests/integration/nativeimage/mp2/package-info.java b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/package-info.java similarity index 77% rename from tests/integration/native-image/mp-2/src/main/java/io/helidon/tests/integration/nativeimage/mp2/package-info.java rename to tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/package-info.java index a7d3a03cd5d..d8656db30e9 100644 --- a/tests/integration/native-image/mp-2/src/main/java/io/helidon/tests/integration/nativeimage/mp2/package-info.java +++ b/tests/integration/packaging/mp-1/src/main/java/io/helidon/tests/integration/packaging/mp1/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Oracle and/or its affiliates. + * Copyright (c) 2020, 2024 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. @@ -14,6 +14,6 @@ * limitations under the License. */ /** - * Application to test GraalVM native-image with Helidon MP. + * Helidon Tests Integration Packaging MP1. */ -package io.helidon.tests.integration.nativeimage.mp2; +package io.helidon.tests.integration.packaging.mp1; diff --git a/tests/integration/native-image/mp-1/src/main/java/module-info.java b/tests/integration/packaging/mp-1/src/main/java/module-info.java similarity index 79% rename from tests/integration/native-image/mp-1/src/main/java/module-info.java rename to tests/integration/packaging/mp-1/src/main/java/module-info.java index d99ace56449..e9c5163e584 100644 --- a/tests/integration/native-image/mp-1/src/main/java/module-info.java +++ b/tests/integration/packaging/mp-1/src/main/java/module-info.java @@ -15,9 +15,10 @@ */ /** - * Application to test GraalVM native-image with Helidon MP. + * Helidon Tests Integration Packaging MP1. */ -module helidon.tests.nimage.mp { +@SuppressWarnings("removal") +module io.helidon.tests.integration.packaging.mp.one { requires io.helidon.microprofile.server; requires io.helidon.security.abac.scope; @@ -40,12 +41,15 @@ // never reach health check CDI extension requires io.helidon.health.checks; - exports io.helidon.tests.integration.nativeimage.mp1; - exports io.helidon.tests.integration.nativeimage.mp1.other; + // needed to compile injection generated classes + requires static io.helidon.inject.runtime; + + exports io.helidon.tests.integration.packaging.mp1; + exports io.helidon.tests.integration.packaging.mp1.other; // opens is needed to inject private fields, create classes in the same package (proxy) - opens io.helidon.tests.integration.nativeimage.mp1; - opens io.helidon.tests.integration.nativeimage.mp1.other; + opens io.helidon.tests.integration.packaging.mp1; + opens io.helidon.tests.integration.packaging.mp1.other; // we need to open the static resource on classpath directory to everybody, as otherwise // static content will not see it diff --git a/tests/integration/native-image/mp-1/src/main/resources/META-INF/beans.xml b/tests/integration/packaging/mp-1/src/main/resources/META-INF/beans.xml similarity index 100% rename from tests/integration/native-image/mp-1/src/main/resources/META-INF/beans.xml rename to tests/integration/packaging/mp-1/src/main/resources/META-INF/beans.xml diff --git a/tests/integration/native-image/mp-1/src/main/resources/META-INF/microprofile-config-test.properties b/tests/integration/packaging/mp-1/src/main/resources/META-INF/microprofile-config-test.properties similarity index 91% rename from tests/integration/native-image/mp-1/src/main/resources/META-INF/microprofile-config-test.properties rename to tests/integration/packaging/mp-1/src/main/resources/META-INF/microprofile-config-test.properties index 6e53ae07943..d09ce1c409c 100644 --- a/tests/integration/native-image/mp-1/src/main/resources/META-INF/microprofile-config-test.properties +++ b/tests/integration/packaging/mp-1/src/main/resources/META-INF/microprofile-config-test.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2019, 2023 Oracle and/or its affiliates. +# Copyright (c) 2019, 2024 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. diff --git a/tests/integration/native-image/mp-1/src/main/resources/META-INF/microprofile-config.properties b/tests/integration/packaging/mp-1/src/main/resources/META-INF/microprofile-config.properties similarity index 89% rename from tests/integration/native-image/mp-1/src/main/resources/META-INF/microprofile-config.properties rename to tests/integration/packaging/mp-1/src/main/resources/META-INF/microprofile-config.properties index 8e491508d95..d5a17f82f33 100644 --- a/tests/integration/native-image/mp-1/src/main/resources/META-INF/microprofile-config.properties +++ b/tests/integration/packaging/mp-1/src/main/resources/META-INF/microprofile-config.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2019, 2023 Oracle and/or its affiliates. +# Copyright (c) 2019, 2024 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. @@ -20,7 +20,7 @@ app.jaxrs.number=142 %test.app.jaxrs.number=42 mp.jwt.verify.publickey.location=/verify-jwk.json -mp.jwt.verify.issuer=native-image-mp1 +mp.jwt.verify.issuer=helidon-tests-packaging-mp1 tracing.service=mp1 tracing.global=false diff --git a/tests/integration/native-image/mp-3/src/main/resources/META-INF/native-image/io.helidon.tests.integration.native-image/helidon-tests-native-image-mp-3/native-image.properties b/tests/integration/packaging/mp-1/src/main/resources/META-INF/native-image/io.helidon.tests.integration.packaging/helidon-tests-integration-packaging-mp1/native-image.properties similarity index 88% rename from tests/integration/native-image/mp-3/src/main/resources/META-INF/native-image/io.helidon.tests.integration.native-image/helidon-tests-native-image-mp-3/native-image.properties rename to tests/integration/packaging/mp-1/src/main/resources/META-INF/native-image/io.helidon.tests.integration.packaging/helidon-tests-integration-packaging-mp1/native-image.properties index 69b9f9e926b..ceb51af7ac5 100644 --- a/tests/integration/native-image/mp-3/src/main/resources/META-INF/native-image/io.helidon.tests.integration.native-image/helidon-tests-native-image-mp-3/native-image.properties +++ b/tests/integration/packaging/mp-1/src/main/resources/META-INF/native-image/io.helidon.tests.integration.packaging/helidon-tests-integration-packaging-mp1/native-image.properties @@ -14,4 +14,4 @@ # limitations under the License. # -Args=--initialize-at-build-time=io.helidon.tests.integration.nativeimage.mp3 +Args=--initialize-at-build-time=io.helidon.tests.integration.packaging.mp1 diff --git a/tests/integration/native-image/mp-1/src/main/resources/logging.properties b/tests/integration/packaging/mp-1/src/main/resources/logging.properties similarity index 95% rename from tests/integration/native-image/mp-1/src/main/resources/logging.properties rename to tests/integration/packaging/mp-1/src/main/resources/logging.properties index 9c31df101c2..f3dd9333243 100644 --- a/tests/integration/native-image/mp-1/src/main/resources/logging.properties +++ b/tests/integration/packaging/mp-1/src/main/resources/logging.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2018, 2023 Oracle and/or its affiliates. +# Copyright (c) 2018, 2024 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. diff --git a/tests/integration/native-image/mp-1/src/main/resources/mp-meta-config.yaml b/tests/integration/packaging/mp-1/src/main/resources/mp-meta-config.yaml similarity index 91% rename from tests/integration/native-image/mp-1/src/main/resources/mp-meta-config.yaml rename to tests/integration/packaging/mp-1/src/main/resources/mp-meta-config.yaml index 7eddde48ee4..1af0a531cc7 100644 --- a/tests/integration/native-image/mp-1/src/main/resources/mp-meta-config.yaml +++ b/tests/integration/packaging/mp-1/src/main/resources/mp-meta-config.yaml @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, 2021 Oracle and/or its affiliates. +# Copyright (c) 2020, 2024 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. @@ -20,10 +20,10 @@ sources: - type: "system-properties" - type: "environment-variables" - type: "yaml" + optional: true path: "mp-config.yaml" - type: "yaml" optional: true classpath: "application.yaml" - type: "properties" classpath: "META-INF/microprofile-config.properties" - diff --git a/tests/integration/native-image/mp-1/src/main/resources/sign-jwk.json b/tests/integration/packaging/mp-1/src/main/resources/sign-jwk.json similarity index 100% rename from tests/integration/native-image/mp-1/src/main/resources/sign-jwk.json rename to tests/integration/packaging/mp-1/src/main/resources/sign-jwk.json diff --git a/tests/integration/native-image/mp-1/src/main/resources/verify-jwk.json b/tests/integration/packaging/mp-1/src/main/resources/verify-jwk.json similarity index 100% rename from tests/integration/native-image/mp-1/src/main/resources/verify-jwk.json rename to tests/integration/packaging/mp-1/src/main/resources/verify-jwk.json diff --git a/tests/integration/native-image/mp-1/src/main/resources/web/resource.txt b/tests/integration/packaging/mp-1/src/main/resources/web/resource.txt similarity index 100% rename from tests/integration/native-image/mp-1/src/main/resources/web/resource.txt rename to tests/integration/packaging/mp-1/src/main/resources/web/resource.txt diff --git a/tests/integration/native-image/mp-1/src/main/resources/web/welcome.txt b/tests/integration/packaging/mp-1/src/main/resources/web/welcome.txt similarity index 100% rename from tests/integration/native-image/mp-1/src/main/resources/web/welcome.txt rename to tests/integration/packaging/mp-1/src/main/resources/web/welcome.txt diff --git a/tests/integration/packaging/mp-1/src/test/java/io/helidon/tests/integration/packaging/mp1/Mp1JarClassPathTestIT.java b/tests/integration/packaging/mp-1/src/test/java/io/helidon/tests/integration/packaging/mp1/Mp1JarClassPathTestIT.java new file mode 100644 index 00000000000..e6a8cabc2bc --- /dev/null +++ b/tests/integration/packaging/mp-1/src/test/java/io/helidon/tests/integration/packaging/mp1/Mp1JarClassPathTestIT.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024 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.tests.integration.packaging.mp1; + +import io.helidon.tests.integration.harness.ProcessRunner.ExecMode; + +import org.junit.jupiter.api.Test; + +class Mp1JarClassPathTestIT extends Mp1PackagingTestIT { + + @Override + ExecMode execMode() { + return ExecMode.CLASS_PATH; + } + + @Test + void testApp() { + doTestApp(); + } +} diff --git a/tests/integration/packaging/mp-1/src/test/java/io/helidon/tests/integration/packaging/mp1/Mp1JarModulePathTestIT.java b/tests/integration/packaging/mp-1/src/test/java/io/helidon/tests/integration/packaging/mp1/Mp1JarModulePathTestIT.java new file mode 100644 index 00000000000..6219c46c711 --- /dev/null +++ b/tests/integration/packaging/mp-1/src/test/java/io/helidon/tests/integration/packaging/mp1/Mp1JarModulePathTestIT.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024 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.tests.integration.packaging.mp1; + +import io.helidon.tests.integration.harness.ProcessRunner.ExecMode; + +import org.junit.jupiter.api.Test; + +class Mp1JarModulePathTestIT extends Mp1PackagingTestIT { + + @Override + ExecMode execMode() { + return ExecMode.MODULE_PATH; + } + + @Test + void testApp() { + doTestApp(); + } +} diff --git a/tests/integration/packaging/mp-1/src/test/java/io/helidon/tests/integration/packaging/mp1/Mp1JlinkModulePathTestIT.java b/tests/integration/packaging/mp-1/src/test/java/io/helidon/tests/integration/packaging/mp1/Mp1JlinkModulePathTestIT.java new file mode 100644 index 00000000000..0763be2cc31 --- /dev/null +++ b/tests/integration/packaging/mp-1/src/test/java/io/helidon/tests/integration/packaging/mp1/Mp1JlinkModulePathTestIT.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024 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.tests.integration.packaging.mp1; + +import io.helidon.tests.integration.harness.ProcessRunner.ExecMode; + +import org.junit.jupiter.api.Test; + +class Mp1JlinkModulePathTestIT extends Mp1PackagingTestIT { + + @Override + ExecMode execMode() { + return ExecMode.JLINK_MODULE_PATH; + } + + @Test + void testApp() { + doTestApp(); + } +} diff --git a/tests/integration/packaging/mp-1/src/test/java/io/helidon/tests/integration/packaging/mp1/Mp1JlinkTestIT.java b/tests/integration/packaging/mp-1/src/test/java/io/helidon/tests/integration/packaging/mp1/Mp1JlinkTestIT.java new file mode 100644 index 00000000000..4990051f946 --- /dev/null +++ b/tests/integration/packaging/mp-1/src/test/java/io/helidon/tests/integration/packaging/mp1/Mp1JlinkTestIT.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024 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.tests.integration.packaging.mp1; + +import io.helidon.tests.integration.harness.ProcessRunner.ExecMode; + +import org.junit.jupiter.api.Test; + +class Mp1JlinkTestIT extends Mp1PackagingTestIT { + + @Override + ExecMode execMode() { + return ExecMode.JLINK_CLASS_PATH; + } + + @Test + void testApp() { + doTestApp(); + } +} diff --git a/tests/integration/packaging/mp-1/src/test/java/io/helidon/tests/integration/packaging/mp1/Mp1NativeTestIT.java b/tests/integration/packaging/mp-1/src/test/java/io/helidon/tests/integration/packaging/mp1/Mp1NativeTestIT.java new file mode 100644 index 00000000000..9edd7bf03e2 --- /dev/null +++ b/tests/integration/packaging/mp-1/src/test/java/io/helidon/tests/integration/packaging/mp1/Mp1NativeTestIT.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024 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.tests.integration.packaging.mp1; + +import io.helidon.tests.integration.harness.ProcessRunner.ExecMode; + +import org.junit.jupiter.api.Test; + +class Mp1NativeTestIT extends Mp1PackagingTestIT { + + @Override + ExecMode execMode() { + return ExecMode.NATIVE; + } + + @Test + void testApp() { + doTestApp(); + } +} diff --git a/tests/integration/packaging/mp-1/src/test/java/io/helidon/tests/integration/packaging/mp1/Mp1PackagingTestIT.java b/tests/integration/packaging/mp-1/src/test/java/io/helidon/tests/integration/packaging/mp1/Mp1PackagingTestIT.java new file mode 100644 index 00000000000..d9c781e7108 --- /dev/null +++ b/tests/integration/packaging/mp-1/src/test/java/io/helidon/tests/integration/packaging/mp1/Mp1PackagingTestIT.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024 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.tests.integration.packaging.mp1; + +import io.helidon.tests.integration.harness.ProcessRunner; +import io.helidon.tests.integration.harness.ProcessRunner.ExecMode; +import io.helidon.tests.integration.harness.ProcessMonitor; +import io.helidon.tests.integration.harness.WaitStrategy; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +abstract class Mp1PackagingTestIT { + + abstract ExecMode execMode(); + + void doTestApp() { + try (ProcessMonitor process = process() + .await(WaitStrategy.waitForCompletion())) { + assertThat(process.get().exitValue(), is(0)); + } + } + + private ProcessMonitor process(String... opts) { + return ProcessRunner.of(execMode()) + .finalName("helidon-tests-integration-packaging-mp-1") + .moduleName("io.helidon.tests.integration.packaging.mp.one") + .mainClass("io.helidon.tests.integration.packaging.mp1.Mp1Main") + .opts(opts) + .start(); + } +} diff --git a/tests/integration/native-image/mp-1/web/resource.txt b/tests/integration/packaging/mp-1/web/resource.txt similarity index 100% rename from tests/integration/native-image/mp-1/web/resource.txt rename to tests/integration/packaging/mp-1/web/resource.txt diff --git a/tests/integration/packaging/mp-2/README.md b/tests/integration/packaging/mp-2/README.md new file mode 100644 index 00000000000..c1bb15061fc --- /dev/null +++ b/tests/integration/packaging/mp-2/README.md @@ -0,0 +1,31 @@ +# Packaging Integration Test MP2 + +This test makes sure the following helidon modules can be compiled into native image: +- JPA in MicroProfile app +- JTA in MicroProfile app + +--- + +To run this test: +```shell +mvn clean verify +mvn clean verify -Pnative-image +mvn clean verify -Pjlink-image +``` + +--- + +Start the database manually: +```shell +docker run -d \ + -name oracledb \ + -e ORACLE_PWD=oracle123 \ + -v ./src/test/resources/init.sql:/opt/oracle/scripts/startup/init.sql \ + -p 1521:1521 \ + container-registry.oracle.com/database/express:latest +``` + +Start the application: +```shell +java -jar target/helidon-tests-integration-packaging-mp-2.jar +``` diff --git a/tests/integration/native-image/mp-2/pom.xml b/tests/integration/packaging/mp-2/pom.xml similarity index 54% rename from tests/integration/native-image/mp-2/pom.xml rename to tests/integration/packaging/mp-2/pom.xml index 6b9b417cbf3..d26f8644a8f 100644 --- a/tests/integration/native-image/mp-2/pom.xml +++ b/tests/integration/packaging/mp-2/pom.xml @@ -25,17 +25,13 @@ 4.1.0-SNAPSHOT ../../../../applications/mp/pom.xml - io.helidon.tests.integration.native-image - helidon-tests-native-image-mp-2 - Helidon Tests Integration GraalVM Native image MP2 - - - This test makes sure the following helidon modules can be compiled into native image: - JPA in MicroProfile app - JTA in - MicroProfile app - + io.helidon.tests.integration.packaging + helidon-tests-integration-packaging-mp-2 + Helidon Tests Integration Packaging MP2 - io.helidon.tests.integration.nativeimage.mp2.Mp2Main + io.helidon.tests.integration.packaging.mp2.Mp2Main + true @@ -55,9 +51,6 @@ io.smallrye jandex - jakarta.persistence jakarta.persistence-api @@ -109,12 +102,28 @@ org.slf4j slf4j-jdk14 - org.junit.jupiter junit-jupiter-api test + + org.hamcrest + hamcrest-all + test + + + io.helidon.tests.integration + helidon-tests-integration-harness + ${project.version} + test + + + + org.testcontainers + junit-jupiter + test + @@ -161,6 +170,102 @@ + + org.apache.maven.plugins + maven-surefire-plugin + + + **/*IT + + + + ${project.build.outputDirectory}/logging.properties + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + ${project.build.outputDirectory}/logging.properties + + + ${redirectTestOutputToFile} + + + + + integration-test + verify + + + + + + + + jar-image + + true + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + **/*Jar*IT + + + + + + + + native-image + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + **/*Native*IT + + + + + + + + jlink-image + + + + io.helidon.build-tools + helidon-maven-plugin + + false + false + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + **/*Jlink*IT + + + + + + + diff --git a/tests/integration/native-image/mp-2/src/main/java/io/helidon/tests/integration/nativeimage/mp2/GreetingEntity.java b/tests/integration/packaging/mp-2/src/main/java/io/helidon/tests/integration/packaging/mp2/GreetingEntity.java similarity index 86% rename from tests/integration/native-image/mp-2/src/main/java/io/helidon/tests/integration/nativeimage/mp2/GreetingEntity.java rename to tests/integration/packaging/mp-2/src/main/java/io/helidon/tests/integration/packaging/mp2/GreetingEntity.java index c5a1974b711..d94c87353ba 100644 --- a/tests/integration/native-image/mp-2/src/main/java/io/helidon/tests/integration/nativeimage/mp2/GreetingEntity.java +++ b/tests/integration/packaging/mp-2/src/main/java/io/helidon/tests/integration/packaging/mp2/GreetingEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. + * Copyright (c) 2020, 2024 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.mp2; +package io.helidon.tests.integration.packaging.mp2; import java.util.Objects; @@ -36,7 +36,7 @@ public class GreetingEntity { private String secondPart; /** - * Creates a new {@link io.helidon.tests.integration.nativeimage.mp2.GreetingEntity}; required by the JPA + * Creates a new {@link GreetingEntity}; required by the JPA * specification and for no other purpose. * * @deprecated Please use the {@link #GreetingEntity(String, String)} constructor instead. @@ -49,7 +49,7 @@ protected GreetingEntity() { } /** - * Creates a new {@link io.helidon.tests.integration.nativeimage.mp2.GreetingEntity}. + * Creates a new {@link GreetingEntity}. * * @param firstPart the first part of the greeting; must not be * {@code null} @@ -97,12 +97,12 @@ public void setSecondPart(final String secondPart) { /** * Returns a {@link String} representation of the second part of - * this {@link io.helidon.tests.integration.nativeimage.mp2.GreetingEntity}. + * this {@link GreetingEntity}. * *

        This method never returns {@code null}.

        * * @return a non-{@code null} {@link String} representation of the - * second part of this {@link io.helidon.tests.integration.nativeimage.mp2.GreetingEntity} + * second part of this {@link GreetingEntity} */ @Override public String toString() { diff --git a/tests/integration/native-image/mp-2/src/main/java/io/helidon/tests/integration/nativeimage/mp2/JaxRsResource.java b/tests/integration/packaging/mp-2/src/main/java/io/helidon/tests/integration/packaging/mp2/JaxRsResource.java similarity index 96% rename from tests/integration/native-image/mp-2/src/main/java/io/helidon/tests/integration/nativeimage/mp2/JaxRsResource.java rename to tests/integration/packaging/mp-2/src/main/java/io/helidon/tests/integration/packaging/mp2/JaxRsResource.java index 6abb6de0ea7..4bf9beb4dd5 100644 --- a/tests/integration/native-image/mp-2/src/main/java/io/helidon/tests/integration/nativeimage/mp2/JaxRsResource.java +++ b/tests/integration/packaging/mp-2/src/main/java/io/helidon/tests/integration/packaging/mp2/JaxRsResource.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. + * Copyright (c) 2020, 2024 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.mp2; +package io.helidon.tests.integration.packaging.mp2; import java.net.URI; diff --git a/tests/integration/native-image/mp-2/src/main/java/io/helidon/tests/integration/nativeimage/mp2/Mp2Main.java b/tests/integration/packaging/mp-2/src/main/java/io/helidon/tests/integration/packaging/mp2/Mp2Main.java similarity index 96% rename from tests/integration/native-image/mp-2/src/main/java/io/helidon/tests/integration/nativeimage/mp2/Mp2Main.java rename to tests/integration/packaging/mp-2/src/main/java/io/helidon/tests/integration/packaging/mp2/Mp2Main.java index f7a4f1fab32..3d18278de7b 100644 --- a/tests/integration/native-image/mp-2/src/main/java/io/helidon/tests/integration/nativeimage/mp2/Mp2Main.java +++ b/tests/integration/packaging/mp-2/src/main/java/io/helidon/tests/integration/packaging/mp2/Mp2Main.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.mp2; +package io.helidon.tests.integration.packaging.mp2; import io.helidon.common.Errors; import io.helidon.microprofile.server.Server; @@ -38,6 +38,7 @@ private Mp2Main() { /** * Application main entry point. + * * @param args command line arguments. */ public static void main(final String[] args) { @@ -109,7 +110,7 @@ private static void validateResponse(Response response, Errors.Collector collect } } else { collector.fatal("Endpoint " + path + " should be accessible. Status received: " - + response.getStatus()); + + response.getStatus()); } } } diff --git a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/package-info.java b/tests/integration/packaging/mp-2/src/main/java/io/helidon/tests/integration/packaging/mp2/package-info.java similarity index 76% rename from tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/package-info.java rename to tests/integration/packaging/mp-2/src/main/java/io/helidon/tests/integration/packaging/mp2/package-info.java index fb60757f945..2b81e097ea0 100644 --- a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/package-info.java +++ b/tests/integration/packaging/mp-2/src/main/java/io/helidon/tests/integration/packaging/mp2/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. + * Copyright (c) 2020, 2024 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. @@ -14,6 +14,6 @@ * limitations under the License. */ /** - * Application to test GraalVM native-image with Helidon MP. + * Helidon Tests Integration Packaging MP2. */ -package io.helidon.tests.integration.nativeimage.mp1; +package io.helidon.tests.integration.packaging.mp2; diff --git a/tests/integration/native-image/mp-2/src/main/resources/META-INF/beans.xml b/tests/integration/packaging/mp-2/src/main/resources/META-INF/beans.xml similarity index 100% rename from tests/integration/native-image/mp-2/src/main/resources/META-INF/beans.xml rename to tests/integration/packaging/mp-2/src/main/resources/META-INF/beans.xml diff --git a/tests/integration/native-image/mp-2/src/main/resources/META-INF/microprofile-config.properties b/tests/integration/packaging/mp-2/src/main/resources/META-INF/microprofile-config.properties similarity index 68% rename from tests/integration/native-image/mp-2/src/main/resources/META-INF/microprofile-config.properties rename to tests/integration/packaging/mp-2/src/main/resources/META-INF/microprofile-config.properties index 515525f15e9..211f5a84b5f 100644 --- a/tests/integration/native-image/mp-2/src/main/resources/META-INF/microprofile-config.properties +++ b/tests/integration/packaging/mp-2/src/main/resources/META-INF/microprofile-config.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2019, 2021 Oracle and/or its affiliates. +# Copyright (c) 2019, 2024 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. @@ -15,11 +15,7 @@ # server.port=8087 features.print-details=true -#javax.sql.DataSource.test.dataSource.url=jdbc:h2:tcp://localhost:9092/test -#javax.sql.DataSource.test.dataSource.user=sa -#javax.sql.DataSource.test.dataSource.password=${EMPTY} -#javax.sql.DataSource.test.dataSourceClassName=org.h2.jdbcx.JdbcDataSource javax.sql.DataSource.test.dataSource.url=jdbc:oracle:thin:@localhost:1521/XE javax.sql.DataSource.test.dataSource.user=system -javax.sql.DataSource.test.dataSource.password=oracle +javax.sql.DataSource.test.dataSource.password=oracle123 javax.sql.DataSource.test.dataSourceClassName=oracle.jdbc.pool.OracleDataSource diff --git a/tests/integration/native-image/mp-2/src/main/resources/META-INF/native-image/io.helidon.tests.integration.native-image/helidon-tests-native-image-mp-2/native-image.properties b/tests/integration/packaging/mp-2/src/main/resources/META-INF/native-image/io.helidon.tests.integration.packaging/helidon-tests-integration-packaging-mp2/native-image.properties similarity index 88% rename from tests/integration/native-image/mp-2/src/main/resources/META-INF/native-image/io.helidon.tests.integration.native-image/helidon-tests-native-image-mp-2/native-image.properties rename to tests/integration/packaging/mp-2/src/main/resources/META-INF/native-image/io.helidon.tests.integration.packaging/helidon-tests-integration-packaging-mp2/native-image.properties index 019b20a2a29..97410fa5a9b 100644 --- a/tests/integration/native-image/mp-2/src/main/resources/META-INF/native-image/io.helidon.tests.integration.native-image/helidon-tests-native-image-mp-2/native-image.properties +++ b/tests/integration/packaging/mp-2/src/main/resources/META-INF/native-image/io.helidon.tests.integration.packaging/helidon-tests-integration-packaging-mp2/native-image.properties @@ -14,4 +14,4 @@ # limitations under the License. # -Args=--initialize-at-build-time=io.helidon.tests.integration.nativeimage.mp2 +Args=--initialize-at-build-time=io.helidon.tests.integration.packaging.mp2 diff --git a/tests/integration/native-image/mp-2/src/main/resources/META-INF/persistence.xml b/tests/integration/packaging/mp-2/src/main/resources/META-INF/persistence.xml similarity index 87% rename from tests/integration/native-image/mp-2/src/main/resources/META-INF/persistence.xml rename to tests/integration/packaging/mp-2/src/main/resources/META-INF/persistence.xml index a9a8c016a8b..1c4ca91b456 100644 --- a/tests/integration/native-image/mp-2/src/main/resources/META-INF/persistence.xml +++ b/tests/integration/packaging/mp-2/src/main/resources/META-INF/persistence.xml @@ -1,7 +1,7 @@ - + + + 4.0.0 + + io.helidon.applications + helidon-mp + 4.1.0-SNAPSHOT + ../../../../applications/mp/pom.xml + + io.helidon.tests.integration.packaging + helidon-tests-integration-packaging-mp-3 + Helidon Tests Integration Packaging MP3 + + + This test uses quickstart application with minimal number of changes + + + + io.helidon.tests.integration.packaging.mp3.Mp3Main + true + + + + + io.helidon.microprofile.bundles + helidon-microprofile + + + io.helidon.inject + helidon-inject-runtime + true + + + io.smallrye + jandex + runtime + true + + + io.helidon.logging + helidon-logging-jul + + + org.junit.jupiter + junit-jupiter-api + test + + + org.hamcrest + hamcrest-all + test + + + io.helidon.tests.integration + helidon-tests-integration-harness + ${project.version} + test + + + + + + + org.graalvm.buildtools + native-maven-plugin + + true + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-libs + + + + + io.smallrye + jandex-maven-plugin + + + make-index + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + **/*IT + + + + ${project.build.outputDirectory}/logging.properties + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + ${project.build.outputDirectory}/logging.properties + + + ${redirectTestOutputToFile} + + + + + integration-test + verify + + + + + + + + + + jar-image + + true + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + **/*Jar*IT + + + + + + + + native-image + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + **/*Native*IT + + + + + + + + jlink-image + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + **/*Jlink*IT + + + + + + + + diff --git a/tests/integration/native-image/mp-3/src/main/java/io/helidon/tests/integration/nativeimage/mp3/GreetResource.java b/tests/integration/packaging/mp-3/src/main/java/io/helidon/tests/integration/packaging/mp3/GreetResource.java similarity index 97% rename from tests/integration/native-image/mp-3/src/main/java/io/helidon/tests/integration/nativeimage/mp3/GreetResource.java rename to tests/integration/packaging/mp-3/src/main/java/io/helidon/tests/integration/packaging/mp3/GreetResource.java index 4c06382723e..91ea9277211 100644 --- a/tests/integration/native-image/mp-3/src/main/java/io/helidon/tests/integration/nativeimage/mp3/GreetResource.java +++ b/tests/integration/packaging/mp-3/src/main/java/io/helidon/tests/integration/packaging/mp3/GreetResource.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022 Oracle and/or its affiliates. + * Copyright (c) 2018, 2024 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.mp3; +package io.helidon.tests.integration.packaging.mp3; import java.util.Collections; diff --git a/tests/integration/native-image/mp-3/src/main/java/io/helidon/tests/integration/nativeimage/mp3/GreetingProvider.java b/tests/integration/packaging/mp-3/src/main/java/io/helidon/tests/integration/packaging/mp3/GreetingProvider.java similarity index 92% rename from tests/integration/native-image/mp-3/src/main/java/io/helidon/tests/integration/nativeimage/mp3/GreetingProvider.java rename to tests/integration/packaging/mp-3/src/main/java/io/helidon/tests/integration/packaging/mp3/GreetingProvider.java index 47e309b4eac..23bfceae9b7 100644 --- a/tests/integration/native-image/mp-3/src/main/java/io/helidon/tests/integration/nativeimage/mp3/GreetingProvider.java +++ b/tests/integration/packaging/mp-3/src/main/java/io/helidon/tests/integration/packaging/mp3/GreetingProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. + * Copyright (c) 2018, 2024 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.mp3; +package io.helidon.tests.integration.packaging.mp3; import java.util.concurrent.atomic.AtomicReference; diff --git a/tests/integration/native-image/mp-3/src/main/java/io/helidon/tests/integration/nativeimage/mp3/Mp3Main.java b/tests/integration/packaging/mp-3/src/main/java/io/helidon/tests/integration/packaging/mp3/Mp3Main.java similarity index 89% rename from tests/integration/native-image/mp-3/src/main/java/io/helidon/tests/integration/nativeimage/mp3/Mp3Main.java rename to tests/integration/packaging/mp-3/src/main/java/io/helidon/tests/integration/packaging/mp3/Mp3Main.java index 83d5da9e999..4c7be7a0751 100644 --- a/tests/integration/native-image/mp-3/src/main/java/io/helidon/tests/integration/nativeimage/mp3/Mp3Main.java +++ b/tests/integration/packaging/mp-3/src/main/java/io/helidon/tests/integration/packaging/mp3/Mp3Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2024 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. @@ -13,8 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -package io.helidon.tests.integration.nativeimage.mp3; +package io.helidon.tests.integration.packaging.mp3; import io.helidon.Main; diff --git a/tests/integration/native-image/mp-3/src/main/java/io/helidon/tests/integration/nativeimage/mp3/RoutingService.java b/tests/integration/packaging/mp-3/src/main/java/io/helidon/tests/integration/packaging/mp3/RoutingService.java similarity index 92% rename from tests/integration/native-image/mp-3/src/main/java/io/helidon/tests/integration/nativeimage/mp3/RoutingService.java rename to tests/integration/packaging/mp-3/src/main/java/io/helidon/tests/integration/packaging/mp3/RoutingService.java index 1aaaf910b79..c703fdcf726 100644 --- a/tests/integration/native-image/mp-3/src/main/java/io/helidon/tests/integration/nativeimage/mp3/RoutingService.java +++ b/tests/integration/packaging/mp-3/src/main/java/io/helidon/tests/integration/packaging/mp3/RoutingService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023 Oracle and/or its affiliates. + * Copyright (c) 2019, 2024 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.mp3; +package io.helidon.tests.integration.packaging.mp3; import io.helidon.microprofile.server.RoutingPath; import io.helidon.webserver.http.HttpRules; diff --git a/tests/integration/native-image/mp-3/src/main/java/io/helidon/tests/integration/nativeimage/mp3/package-info.java b/tests/integration/packaging/mp-3/src/main/java/io/helidon/tests/integration/packaging/mp3/package-info.java similarity index 84% rename from tests/integration/native-image/mp-3/src/main/java/io/helidon/tests/integration/nativeimage/mp3/package-info.java rename to tests/integration/packaging/mp-3/src/main/java/io/helidon/tests/integration/packaging/mp3/package-info.java index d67a4e663c5..c5ad9264e63 100644 --- a/tests/integration/native-image/mp-3/src/main/java/io/helidon/tests/integration/nativeimage/mp3/package-info.java +++ b/tests/integration/packaging/mp-3/src/main/java/io/helidon/tests/integration/packaging/mp3/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021 Oracle and/or its affiliates. + * Copyright (c) 2018, 2024 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. @@ -17,4 +17,4 @@ /** * Quickstart MicroProfile example. */ -package io.helidon.tests.integration.nativeimage.mp3; +package io.helidon.tests.integration.packaging.mp3; diff --git a/tests/integration/native-image/mp-3/src/main/java/module-info.java b/tests/integration/packaging/mp-3/src/main/java/module-info.java similarity index 68% rename from tests/integration/native-image/mp-3/src/main/java/module-info.java rename to tests/integration/packaging/mp-3/src/main/java/module-info.java index 4093f443cdb..8ed300e2f52 100644 --- a/tests/integration/native-image/mp-3/src/main/java/module-info.java +++ b/tests/integration/packaging/mp-3/src/main/java/module-info.java @@ -15,14 +15,14 @@ */ /** - * Quickstart MicroProfile example. + * Helidon Tests Integration Packaging MP3. */ -module helidon.tests.nimage.quickstartmp { +module io.helidon.tests.integration.packaging.mp.three { + requires java.logging; requires io.helidon.microprofile.bundle; - exports io.helidon.tests.integration.nativeimage.mp3; + exports io.helidon.tests.integration.packaging.mp3; - opens io.helidon.tests.integration.nativeimage.mp3 to weld.core.impl, org.glassfish.hk2.utilities, io.helidon.microprofile.cdi; - + opens io.helidon.tests.integration.packaging.mp3 to weld.core.impl, org.glassfish.hk2.utilities, io.helidon.microprofile.cdi; } diff --git a/tests/integration/native-image/mp-3/src/main/resources/META-INF/beans.xml b/tests/integration/packaging/mp-3/src/main/resources/META-INF/beans.xml similarity index 100% rename from tests/integration/native-image/mp-3/src/main/resources/META-INF/beans.xml rename to tests/integration/packaging/mp-3/src/main/resources/META-INF/beans.xml diff --git a/tests/integration/native-image/mp-3/src/main/resources/META-INF/microprofile-config-test.properties b/tests/integration/packaging/mp-3/src/main/resources/META-INF/microprofile-config-test.properties similarity index 90% rename from tests/integration/native-image/mp-3/src/main/resources/META-INF/microprofile-config-test.properties rename to tests/integration/packaging/mp-3/src/main/resources/META-INF/microprofile-config-test.properties index b242148a897..aa892f4178f 100644 --- a/tests/integration/native-image/mp-3/src/main/resources/META-INF/microprofile-config-test.properties +++ b/tests/integration/packaging/mp-3/src/main/resources/META-INF/microprofile-config-test.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2021 Oracle and/or its affiliates. +# Copyright (c) 2021, 2024 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. diff --git a/tests/integration/native-image/mp-3/src/main/resources/META-INF/microprofile-config.properties b/tests/integration/packaging/mp-3/src/main/resources/META-INF/microprofile-config.properties similarity index 92% rename from tests/integration/native-image/mp-3/src/main/resources/META-INF/microprofile-config.properties rename to tests/integration/packaging/mp-3/src/main/resources/META-INF/microprofile-config.properties index 496292ab203..9a1514cc474 100644 --- a/tests/integration/native-image/mp-3/src/main/resources/META-INF/microprofile-config.properties +++ b/tests/integration/packaging/mp-3/src/main/resources/META-INF/microprofile-config.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, 2023 Oracle and/or its affiliates. +# Copyright (c) 2020, 2024 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. diff --git a/tests/integration/packaging/mp-3/src/main/resources/META-INF/native-image/io.helidon.tests.integration.packaging/helidon-tests-integration-packaging-mp-3/native-image.properties b/tests/integration/packaging/mp-3/src/main/resources/META-INF/native-image/io.helidon.tests.integration.packaging/helidon-tests-integration-packaging-mp-3/native-image.properties new file mode 100644 index 00000000000..af277f9d118 --- /dev/null +++ b/tests/integration/packaging/mp-3/src/main/resources/META-INF/native-image/io.helidon.tests.integration.packaging/helidon-tests-integration-packaging-mp-3/native-image.properties @@ -0,0 +1,17 @@ +# +# Copyright (c) 2023, 2024 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. +# + +Args=--initialize-at-build-time=io.helidon.tests.integration.packaging.mp3 diff --git a/tests/integration/native-image/mp-3/src/main/resources/logging.properties b/tests/integration/packaging/mp-3/src/main/resources/logging.properties similarity index 100% rename from tests/integration/native-image/mp-3/src/main/resources/logging.properties rename to tests/integration/packaging/mp-3/src/main/resources/logging.properties diff --git a/tests/integration/packaging/mp-3/src/test/java/io/helidon/tests/integration/packaging/mp3/Mp3JarClassPathTestIT.java b/tests/integration/packaging/mp-3/src/test/java/io/helidon/tests/integration/packaging/mp3/Mp3JarClassPathTestIT.java new file mode 100644 index 00000000000..ee9ea832442 --- /dev/null +++ b/tests/integration/packaging/mp-3/src/test/java/io/helidon/tests/integration/packaging/mp3/Mp3JarClassPathTestIT.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 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.tests.integration.packaging.mp3; + +import io.helidon.tests.integration.harness.ProcessRunner.ExecMode; + +import org.junit.jupiter.api.Test; + +class Mp3JarClassPathTestIT extends Mp3PackagingTestIT { + + @Override + ExecMode execMode() { + return ExecMode.CLASS_PATH; + } + + @Test + void testExitOnStarted() { + doTestExitOnStarted(); + } + + @Test + void testGreetResource() { + doTestGreetResource(); + } +} diff --git a/tests/integration/packaging/mp-3/src/test/java/io/helidon/tests/integration/packaging/mp3/Mp3JarModulePathTestIT.java b/tests/integration/packaging/mp-3/src/test/java/io/helidon/tests/integration/packaging/mp3/Mp3JarModulePathTestIT.java new file mode 100644 index 00000000000..de202f2af13 --- /dev/null +++ b/tests/integration/packaging/mp-3/src/test/java/io/helidon/tests/integration/packaging/mp3/Mp3JarModulePathTestIT.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 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.tests.integration.packaging.mp3; + +import io.helidon.tests.integration.harness.ProcessRunner.ExecMode; + +import org.junit.jupiter.api.Test; + +class Mp3JarModulePathTestIT extends Mp3PackagingTestIT { + + @Override + ExecMode execMode() { + return ExecMode.MODULE_PATH; + } + + @Test + void testExitOnStarted() { + doTestExitOnStarted(); + } + + @Test + void testGreetResource() { + doTestGreetResource(); + } +} diff --git a/tests/integration/packaging/mp-3/src/test/java/io/helidon/tests/integration/packaging/mp3/Mp3JlinkModulePathTestIT.java b/tests/integration/packaging/mp-3/src/test/java/io/helidon/tests/integration/packaging/mp3/Mp3JlinkModulePathTestIT.java new file mode 100644 index 00000000000..f4c531aadb9 --- /dev/null +++ b/tests/integration/packaging/mp-3/src/test/java/io/helidon/tests/integration/packaging/mp3/Mp3JlinkModulePathTestIT.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 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.tests.integration.packaging.mp3; + +import io.helidon.tests.integration.harness.ProcessRunner.ExecMode; + +import org.junit.jupiter.api.Test; + +class Mp3JlinkModulePathTestIT extends Mp3PackagingTestIT { + + @Override + ExecMode execMode() { + return ExecMode.JLINK_MODULE_PATH; + } + + @Test + void testExitOnStarted() { + doTestExitOnStarted(); + } + + @Test + void testGreetResource() { + doTestGreetResource(); + } +} diff --git a/tests/integration/packaging/mp-3/src/test/java/io/helidon/tests/integration/packaging/mp3/Mp3JlinkTestIT.java b/tests/integration/packaging/mp-3/src/test/java/io/helidon/tests/integration/packaging/mp3/Mp3JlinkTestIT.java new file mode 100644 index 00000000000..035d5a1a533 --- /dev/null +++ b/tests/integration/packaging/mp-3/src/test/java/io/helidon/tests/integration/packaging/mp3/Mp3JlinkTestIT.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 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.tests.integration.packaging.mp3; + +import io.helidon.tests.integration.harness.ProcessRunner.ExecMode; + +import org.junit.jupiter.api.Test; + +class Mp3JlinkTestIT extends Mp3PackagingTestIT { + + @Override + ExecMode execMode() { + return ExecMode.JLINK_CLASS_PATH; + } + + @Test + void testExitOnStarted() { + doTestExitOnStarted(); + } + + @Test + void testGreetResource() { + doTestGreetResource(); + } +} diff --git a/tests/integration/packaging/mp-3/src/test/java/io/helidon/tests/integration/packaging/mp3/Mp3NativeTestIT.java b/tests/integration/packaging/mp-3/src/test/java/io/helidon/tests/integration/packaging/mp3/Mp3NativeTestIT.java new file mode 100644 index 00000000000..50cf1bf1063 --- /dev/null +++ b/tests/integration/packaging/mp-3/src/test/java/io/helidon/tests/integration/packaging/mp3/Mp3NativeTestIT.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 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.tests.integration.packaging.mp3; + +import io.helidon.tests.integration.harness.ProcessRunner.ExecMode; + +import org.junit.jupiter.api.Test; + +class Mp3NativeTestIT extends Mp3PackagingTestIT { + + @Override + ExecMode execMode() { + return ExecMode.NATIVE; + } + + @Test + void testExitOnStarted() { + doTestExitOnStarted(); + } + + @Test + void testGreetResource() { + doTestGreetResource(); + } +} diff --git a/tests/integration/packaging/mp-3/src/test/java/io/helidon/tests/integration/packaging/mp3/Mp3PackagingTestIT.java b/tests/integration/packaging/mp-3/src/test/java/io/helidon/tests/integration/packaging/mp3/Mp3PackagingTestIT.java new file mode 100644 index 00000000000..39aa02e66a2 --- /dev/null +++ b/tests/integration/packaging/mp-3/src/test/java/io/helidon/tests/integration/packaging/mp3/Mp3PackagingTestIT.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2024 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.tests.integration.packaging.mp3; + +import java.util.Map; + +import io.helidon.http.Status; +import io.helidon.tests.integration.harness.ProcessRunner; +import io.helidon.tests.integration.harness.ProcessRunner.ExecMode; +import io.helidon.tests.integration.harness.ProcessMonitor; +import io.helidon.tests.integration.harness.WaitStrategy; +import io.helidon.webclient.api.ClientResponseTyped; +import io.helidon.webclient.api.WebClient; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +abstract class Mp3PackagingTestIT { + + abstract ExecMode execMode(); + + void doTestExitOnStarted() { + try (ProcessMonitor process = process(Map.of("exit.on.started", "!")) + .await(WaitStrategy.waitForCompletion())) { + + assertThat(process.get().exitValue(), is(0)); + } + } + + void doTestGreetResource() { + try (ProcessMonitor process = process(Map.of()) + .await(WaitStrategy.waitForPort())) { + + WebClient client = WebClient.builder() + .baseUri("http://localhost:" + process.port()) + .build(); + ClientResponseTyped response = client.get("/greet/Joe").request(String.class); + assertThat(response.status(), is(Status.OK_200)); + assertThat(response.entity(), is("{\"message\":\"Hello Joe!\"}")); + } + } + + private ProcessMonitor process(Map properties) { + return ProcessRunner.of(execMode()) + .finalName("helidon-tests-integration-packaging-mp-3") + .moduleName("io.helidon.tests.integration.packaging.mp.three") + .mainClass("io.helidon.tests.integration.packaging.mp3.Mp3Main") + .properties(properties) + .start(); + } +} diff --git a/tests/integration/native-image/pom.xml b/tests/integration/packaging/pom.xml similarity index 84% rename from tests/integration/native-image/pom.xml rename to tests/integration/packaging/pom.xml index b9554569dbd..03cf9f36325 100644 --- a/tests/integration/native-image/pom.xml +++ b/tests/integration/packaging/pom.xml @@ -27,11 +27,12 @@ ../pom.xml pom - helidon-tests-integration-native-image - Helidon Tests Integration GraalVM Native image + io.helidon.tests.integration.packaging + helidon-tests-integration-packaging + Helidon Tests Integration Packaging - A set of tests that make sure various Helidon modules can compile with native-image. + A set of tests that verify the Helidon packaging variants (native-image, jlink, jar). @@ -41,5 +42,4 @@ mp-3 se-1 - diff --git a/tests/integration/packaging/se-1/README.md b/tests/integration/packaging/se-1/README.md new file mode 100644 index 00000000000..cfe2e12e72b --- /dev/null +++ b/tests/integration/packaging/se-1/README.md @@ -0,0 +1,8 @@ +# Packaging Integration Test SE1 + +To run this test: +```shell +mvn clean verify +mvn clean verify -Pnative-image +mvn clean verify -Pjlink-image +``` diff --git a/tests/integration/native-image/se-1/conf/overrides.yaml b/tests/integration/packaging/se-1/conf/overrides.yaml similarity index 91% rename from tests/integration/native-image/se-1/conf/overrides.yaml rename to tests/integration/packaging/se-1/conf/overrides.yaml index 9028de61d52..ea4f1ab111e 100644 --- a/tests/integration/native-image/se-1/conf/overrides.yaml +++ b/tests/integration/packaging/se-1/conf/overrides.yaml @@ -1,5 +1,5 @@ # -# Copyright (c) 2022, 2023 Oracle and/or its affiliates. +# Copyright (c) 2022, 2024 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. diff --git a/tests/integration/packaging/se-1/pom.xml b/tests/integration/packaging/se-1/pom.xml new file mode 100644 index 00000000000..9e942340afd --- /dev/null +++ b/tests/integration/packaging/se-1/pom.xml @@ -0,0 +1,234 @@ + + + + + 4.0.0 + + io.helidon.applications + helidon-se + 4.1.0-SNAPSHOT + ../../../../applications/se/pom.xml + + io.helidon.tests.integration.packaging + helidon-tests-integration-packaging-se-1 + Helidon Tests Integration Packaging SE1 + + + io.helidon.tests.integration.packaging.se1.Se1Main + true + + + + + io.helidon.webserver + helidon-webserver + + + io.helidon.webserver + helidon-webserver-static-content + + + io.helidon.webserver + helidon-webserver-websocket + + + io.helidon.http.media + helidon-http-media-jsonp + + + io.helidon.http.media + helidon-http-media-jsonb + + + io.helidon.config + helidon-config-yaml + + + io.helidon.tracing + helidon-tracing + + + io.helidon.tracing.providers + helidon-tracing-providers-zipkin + + + io.helidon.http.encoding + helidon-http-encoding-gzip + + + io.helidon.webserver.observe + helidon-webserver-observe-health + + + io.helidon.webserver.observe + helidon-webserver-observe-tracing + + + io.helidon.webclient + helidon-webclient + + + helidon-webclient-tracing + io.helidon.webclient + + + io.helidon.common + helidon-common-reactive + + + io.helidon.logging + helidon-logging-common + + + io.helidon.tests.integration.packaging + helidon-tests-integration-packaging-static-content + ${project.version} + + + io.helidon.logging + helidon-logging-jul + runtime + + + org.junit.jupiter + junit-jupiter-api + test + + + org.hamcrest + hamcrest-all + test + + + io.helidon.tests.integration + helidon-tests-integration-harness + ${project.version} + test + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-libs + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + **/*IT + + + + ${project.build.outputDirectory}/logging.properties + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + ${project.build.outputDirectory}/logging.properties + + + ${redirectTestOutputToFile} + + + + + integration-test + verify + + + + + + + + + + jar-image + + true + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + **/*Jar*IT + + + + + + + + native-image + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + **/*Native*IT + + + + + + + + jlink-image + + + + io.helidon.build-tools + helidon-maven-plugin + + -Dapp.static.path=../../web + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + **/*Jlink*IT + + + + + + + + diff --git a/tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/Animal.java b/tests/integration/packaging/se-1/src/main/java/io/helidon/tests/integration/packaging/se1/Animal.java similarity index 91% rename from tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/Animal.java rename to tests/integration/packaging/se-1/src/main/java/io/helidon/tests/integration/packaging/se1/Animal.java index b44b8aefa7e..cf6731596db 100644 --- a/tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/Animal.java +++ b/tests/integration/packaging/se-1/src/main/java/io/helidon/tests/integration/packaging/se1/Animal.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. + * Copyright (c) 2022, 2024 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.se1; +package io.helidon.tests.integration.packaging.se1; import io.helidon.common.Reflected; diff --git a/tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/GreetService.java b/tests/integration/packaging/se-1/src/main/java/io/helidon/tests/integration/packaging/se1/GreetService.java similarity index 85% rename from tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/GreetService.java rename to tests/integration/packaging/se-1/src/main/java/io/helidon/tests/integration/packaging/se1/GreetService.java index 043128e7fbf..029b833fcf3 100644 --- a/tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/GreetService.java +++ b/tests/integration/packaging/se-1/src/main/java/io/helidon/tests/integration/packaging/se1/GreetService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. + * Copyright (c) 2022, 2024 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. @@ -14,11 +14,10 @@ * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.se1; +package io.helidon.tests.integration.packaging.se1; import java.util.Collections; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Consumer; import io.helidon.config.Config; import io.helidon.http.Status; @@ -32,20 +31,8 @@ import jakarta.json.JsonObject; /** - * 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 + * A simple service to greet you. */ - class GreetService implements HttpService { private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); @@ -60,7 +47,7 @@ class GreetService implements HttpService { // initial value greeting.set(greetingConfig.asString().orElse("Ciao")); - greetingConfig.onChange((Consumer) cfg -> greeting.set(cfg.asString().orElse("Ciao"))); + greetingConfig.onChange(cfg -> greeting.set(cfg.asString().orElse("Ciao"))); } @Override diff --git a/tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/MockZipkinService.java b/tests/integration/packaging/se-1/src/main/java/io/helidon/tests/integration/packaging/se1/MockZipkinService.java similarity index 51% rename from tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/MockZipkinService.java rename to tests/integration/packaging/se-1/src/main/java/io/helidon/tests/integration/packaging/se1/MockZipkinService.java index 192a929f5ae..81766c9210d 100644 --- a/tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/MockZipkinService.java +++ b/tests/integration/packaging/se-1/src/main/java/io/helidon/tests/integration/packaging/se1/MockZipkinService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023 Oracle and/or its affiliates. + * Copyright (c) 2020, 2024 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. @@ -14,13 +14,13 @@ * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.se1; +package io.helidon.tests.integration.packaging.se1; import java.lang.System.Logger.Level; +import java.util.List; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; -import java.util.zip.GZIPInputStream; import io.helidon.common.reactive.Single; import io.helidon.webserver.http.HttpRules; @@ -28,28 +28,24 @@ import io.helidon.webserver.http.ServerRequest; import io.helidon.webserver.http.ServerResponse; -import jakarta.json.Json; -import jakarta.json.JsonPointer; -import jakarta.json.JsonString; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; import jakarta.json.JsonValue; class MockZipkinService implements HttpService { private static final System.Logger LOGGER = System.getLogger(MockZipkinService.class.getName()); - final static JsonPointer TAGS_POINTER = Json.createPointer("/tags"); - final static JsonPointer COMPONENT_POINTER = Json.createPointer("/tags/component"); - - private final Set filteredComponents; + private final Set components; private final AtomicReference> next = new AtomicReference<>(new CompletableFuture<>()); /** * Create mock of the Zipkin listening on /api/v2/spans. * - * @param filteredComponents listen only for traces with component tag having one of specified values + * @param components listen only for traces with component tag having one of specified values */ - MockZipkinService(Set filteredComponents) { - this.filteredComponents = filteredComponents; + MockZipkinService(Set components) { + this.components = components; } @Override @@ -67,26 +63,18 @@ Single next() { } private void mockZipkin(ServerRequest request, ServerResponse response) { - try { - request.query().all("serviceName").forEach(s -> System.out.println(">>>" + s)); - - GZIPInputStream is = new GZIPInputStream(request.content() - .inputStream()); - Json.createReader(is).readArray() - .stream() - .map(JsonValue::asJsonObject) - .filter(json -> - TAGS_POINTER.containsValue(json) - && COMPONENT_POINTER.containsValue(json) - && filteredComponents.stream() - .anyMatch(s -> s.equals(((JsonString) COMPONENT_POINTER.getValue(json)).getString())) - ) - .peek(json -> LOGGER.log(Level.INFO, json.toString())) - .forEach(e -> next.getAndSet(new CompletableFuture<>()).complete(e)); + JsonArray entity = request.content().as(JsonArray.class); + List spans = entity.stream() + .map(JsonValue::asJsonObject) + .filter(o -> o.containsKey("tags")) + .filter(o -> components.contains(o.getJsonObject("tags").getString("component"))) + .toList(); - response.send(); - } catch (Exception e) { - response.send(e); + for (JsonObject span : spans) { + LOGGER.log(Level.INFO, span.toString()); + next.getAndSet(new CompletableFuture<>()).complete(span); } + + response.send(); } } diff --git a/tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/Se1Main.java b/tests/integration/packaging/se-1/src/main/java/io/helidon/tests/integration/packaging/se1/Se1Main.java similarity index 81% rename from tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/Se1Main.java rename to tests/integration/packaging/se-1/src/main/java/io/helidon/tests/integration/packaging/se1/Se1Main.java index f964d708963..3346e74b595 100644 --- a/tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/Se1Main.java +++ b/tests/integration/packaging/se-1/src/main/java/io/helidon/tests/integration/packaging/se1/Se1Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023 Oracle and/or its affiliates. + * Copyright (c) 2019, 2024 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. @@ -14,12 +14,15 @@ * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.se1; +package io.helidon.tests.integration.packaging.se1; +import java.nio.file.Path; import java.nio.file.Paths; +import java.util.List; import java.util.Set; import io.helidon.config.Config; +import io.helidon.config.ConfigSources; import io.helidon.config.FileSystemWatcher; import io.helidon.health.HealthCheckResponse; import io.helidon.logging.common.LogConfig; @@ -61,19 +64,24 @@ static WebServer startServer() { // load logging configuration LogConfig.configureRuntime(); - // By default this will pick up application.yaml from the classpath + // By default, this will pick up application.yaml from the classpath Config config = buildConfig(); + HealthObserver health = HealthObserver.builder() .addCheck(() -> HealthCheckResponse.builder() .detail("timestamp", System.currentTimeMillis()) .build()) .build(); - ObserveFeature observe = ObserveFeature.just(health); + + ObserveFeature observe = ObserveFeature.builder() + .config(config) + .addObserver(health) + .build(); // Get webserver config from the "server" section of application.yaml WebServer server = WebServer.builder() - .port(7076) + .config(config.get("server")) .addFeature(observe) .addRouting(createRouting(config)) .addRouting(WsRouting.builder() @@ -88,12 +96,14 @@ static WebServer startServer() { private static Config buildConfig() { return Config.builder() - .sources( + .sources(List.of( + ConfigSources.systemProperties(), + ConfigSources.environmentVariables(), classpath("application-test.yaml").optional(), file("conf/overrides.yaml") .changeWatcher(FileSystemWatcher.create()) .optional(), - classpath("application.yaml")) + classpath("application.yaml"))) .build(); } @@ -109,8 +119,12 @@ private static HttpRouting.Builder createRouting(Config config) { MockZipkinService zipkinService = new MockZipkinService(Set.of("helidon-webclient")); WebClientService webClientService = new WebClientService(config, zipkinService); + Path web = config.get("app.static.path") + .as(Path.class) + .orElseThrow(() -> new IllegalStateException("app static path is not present")); + return HttpRouting.builder() - .register("/static/path", StaticContentService.create(Paths.get("web"))) + .register("/static/path", StaticContentService.create(web)) .register("/static/classpath", StaticContentService.create("web")) .register("/static/jar", StaticContentService.create("web-jar")) .register("/greet", greetService) diff --git a/tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/WebClientService.java b/tests/integration/packaging/se-1/src/main/java/io/helidon/tests/integration/packaging/se1/WebClientService.java similarity index 94% rename from tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/WebClientService.java rename to tests/integration/packaging/se-1/src/main/java/io/helidon/tests/integration/packaging/se1/WebClientService.java index 06b2484c00e..fc235b61d40 100644 --- a/tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/WebClientService.java +++ b/tests/integration/packaging/se-1/src/main/java/io/helidon/tests/integration/packaging/se1/WebClientService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023 Oracle and/or its affiliates. + * Copyright (c) 2020, 2024 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.se1; +package io.helidon.tests.integration.packaging.se1; import java.io.PrintWriter; import java.io.StringWriter; @@ -44,9 +44,9 @@ class WebClientService implements HttpService { private final MockZipkinService zipkinService; private final String context; - public WebClientService(Config config, MockZipkinService zipkinService) { + WebClientService(Config config, MockZipkinService zipkinService) { this.zipkinService = zipkinService; - this.context = "http://localhost:" + config.get("port").asInt().orElse(7076); + this.context = "http://localhost:" + config.get("server.port").asInt().orElse(7076); client = WebClient.builder() .baseUri(context) .addHeader(HeaderNames.ACCEPT, MediaTypes.APPLICATION_JSON.text()) diff --git a/tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/WebSocketEndpoint.java b/tests/integration/packaging/se-1/src/main/java/io/helidon/tests/integration/packaging/se1/WebSocketEndpoint.java similarity index 92% rename from tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/WebSocketEndpoint.java rename to tests/integration/packaging/se-1/src/main/java/io/helidon/tests/integration/packaging/se1/WebSocketEndpoint.java index 24af59bddd0..9e06c8e896a 100644 --- a/tests/integration/native-image/se-1/src/main/java/io/helidon/tests/integration/nativeimage/se1/WebSocketEndpoint.java +++ b/tests/integration/packaging/se-1/src/main/java/io/helidon/tests/integration/packaging/se1/WebSocketEndpoint.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023 Oracle and/or its affiliates. + * Copyright (c) 2020, 2024 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.se1; +package io.helidon.tests.integration.packaging.se1; import java.lang.System.Logger.Level; diff --git a/tests/integration/native-image/se-1/src/main/resources/META-INF/native-image/io.helidon.tests.integration.native-image/helidon-tests-native-image-se-1/resource-config.json b/tests/integration/packaging/se-1/src/main/resources/META-INF/native-image/io.helidon.tests.integration.packaging/helidon-tests-integration-packaging-se-1/resource-config.json similarity index 100% rename from tests/integration/native-image/se-1/src/main/resources/META-INF/native-image/io.helidon.tests.integration.native-image/helidon-tests-native-image-se-1/resource-config.json rename to tests/integration/packaging/se-1/src/main/resources/META-INF/native-image/io.helidon.tests.integration.packaging/helidon-tests-integration-packaging-se-1/resource-config.json diff --git a/tests/integration/native-image/se-1/src/main/resources/application.yaml b/tests/integration/packaging/se-1/src/main/resources/application.yaml similarity index 89% rename from tests/integration/native-image/se-1/src/main/resources/application.yaml rename to tests/integration/packaging/se-1/src/main/resources/application.yaml index 7b360e1bd65..7e063a53a48 100644 --- a/tests/integration/native-image/se-1/src/main/resources/application.yaml +++ b/tests/integration/packaging/se-1/src/main/resources/application.yaml @@ -1,5 +1,5 @@ # -# Copyright (c) 2018, 2023 Oracle and/or its affiliates. +# Copyright (c) 2018, 2024 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. @@ -25,7 +25,7 @@ tracing: service: "helidon-se" protocol: "http" host: "localhost" - port: 7076 + port: "${server.port}" api-version: 2 # mocked zipkin path: "/zipkin/api/v2/spans" @@ -34,4 +34,4 @@ client: follow-redirects: true max-redirects: 5 services: - tracing: \ No newline at end of file + tracing: diff --git a/tests/integration/native-image/se-1/src/main/resources/logging.properties b/tests/integration/packaging/se-1/src/main/resources/logging.properties similarity index 100% rename from tests/integration/native-image/se-1/src/main/resources/logging.properties rename to tests/integration/packaging/se-1/src/main/resources/logging.properties diff --git a/tests/integration/native-image/se-1/src/main/resources/web/resource.txt b/tests/integration/packaging/se-1/src/main/resources/web/resource.txt similarity index 100% rename from tests/integration/native-image/se-1/src/main/resources/web/resource.txt rename to tests/integration/packaging/se-1/src/main/resources/web/resource.txt diff --git a/tests/integration/packaging/se-1/src/test/java/io/helidon/tests/integration/packaging/se1/Se1JarClassPathTestIT.java b/tests/integration/packaging/se-1/src/test/java/io/helidon/tests/integration/packaging/se1/Se1JarClassPathTestIT.java new file mode 100644 index 00000000000..7aab6b52d9b --- /dev/null +++ b/tests/integration/packaging/se-1/src/test/java/io/helidon/tests/integration/packaging/se1/Se1JarClassPathTestIT.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 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.tests.integration.packaging.se1; + +import io.helidon.tests.integration.harness.ProcessRunner.ExecMode; + +import org.junit.jupiter.api.Test; + +class Se1JarClassPathTestIT extends Se1PackagingTestIT { + + @Override + ExecMode execMode() { + return ExecMode.CLASS_PATH; + } + + @Test + void testExitOnStarted() { + doTestExitOnStarted(); + } + + @Test + void testWebClientService() { + doTestWebClientService(); + } +} diff --git a/tests/integration/packaging/se-1/src/test/java/io/helidon/tests/integration/packaging/se1/Se1JlinkTestIT.java b/tests/integration/packaging/se-1/src/test/java/io/helidon/tests/integration/packaging/se1/Se1JlinkTestIT.java new file mode 100644 index 00000000000..f5fbd612518 --- /dev/null +++ b/tests/integration/packaging/se-1/src/test/java/io/helidon/tests/integration/packaging/se1/Se1JlinkTestIT.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 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.tests.integration.packaging.se1; + +import io.helidon.tests.integration.harness.ProcessRunner.ExecMode; + +import org.junit.jupiter.api.Test; + +class Se1JlinkTestIT extends Se1PackagingTestIT { + + @Override + ExecMode execMode() { + return ExecMode.JLINK_CLASS_PATH; + } + + @Test + void testExitOnStarted() { + doTestExitOnStarted(); + } + + @Test + void testWebClientService() { + doTestWebClientService(); + } +} diff --git a/tests/integration/packaging/se-1/src/test/java/io/helidon/tests/integration/packaging/se1/Se1NativeTestIT.java b/tests/integration/packaging/se-1/src/test/java/io/helidon/tests/integration/packaging/se1/Se1NativeTestIT.java new file mode 100644 index 00000000000..ef7473132b4 --- /dev/null +++ b/tests/integration/packaging/se-1/src/test/java/io/helidon/tests/integration/packaging/se1/Se1NativeTestIT.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 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.tests.integration.packaging.se1; + +import io.helidon.tests.integration.harness.ProcessRunner.ExecMode; + +import org.junit.jupiter.api.Test; + +class Se1NativeTestIT extends Se1PackagingTestIT { + + @Override + ExecMode execMode() { + return ExecMode.NATIVE; + } + + @Test + void testExitOnStarted() { + doTestExitOnStarted(); + } + + @Test + void testWebClientService() { + doTestWebClientService(); + } +} diff --git a/tests/integration/packaging/se-1/src/test/java/io/helidon/tests/integration/packaging/se1/Se1PackagingTestIT.java b/tests/integration/packaging/se-1/src/test/java/io/helidon/tests/integration/packaging/se1/Se1PackagingTestIT.java new file mode 100644 index 00000000000..1379fd0368e --- /dev/null +++ b/tests/integration/packaging/se-1/src/test/java/io/helidon/tests/integration/packaging/se1/Se1PackagingTestIT.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2024 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.tests.integration.packaging.se1; + +import java.nio.file.Path; +import java.util.Map; + +import io.helidon.http.Status; +import io.helidon.tests.integration.harness.ProcessRunner; +import io.helidon.tests.integration.harness.ProcessRunner.ExecMode; +import io.helidon.tests.integration.harness.ProcessMonitor; +import io.helidon.tests.integration.harness.WaitStrategy; +import io.helidon.webclient.api.ClientResponseTyped; +import io.helidon.webclient.api.WebClient; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +abstract class Se1PackagingTestIT { + + abstract ExecMode execMode(); + + void doTestExitOnStarted() { + try (ProcessMonitor process = process(Map.of("exit.on.started", "!")) + .await(WaitStrategy.waitForCompletion())) { + + assertThat(process.get().exitValue(), is(0)); + } + } + + void doTestWebClientService() { + try (ProcessMonitor process = process(Map.of()) + .await(WaitStrategy.waitForPort())) { + + WebClient client = WebClient.builder() + .baseUri("http://localhost:" + process.port()) + .build(); + ClientResponseTyped response = client.get("/wc/test").request(String.class); + assertThat(response.status(), is(Status.OK_200)); + assertThat(response.entity(), is("ALL TESTS PASSED!\n")); + } + } + + private ProcessMonitor process(Map properties) { + return ProcessRunner.of(execMode()) + .finalName("helidon-tests-integration-packaging-se-1") + .properties(properties) + .properties(Map.of("app.static.path", Path.of("web").toAbsolutePath())) + .port(0) + .start(); + } +} diff --git a/tests/integration/native-image/se-1/web/resource.txt b/tests/integration/packaging/se-1/web/resource.txt similarity index 100% rename from tests/integration/native-image/se-1/web/resource.txt rename to tests/integration/packaging/se-1/web/resource.txt diff --git a/tests/integration/native-image/static-content/pom.xml b/tests/integration/packaging/static-content/pom.xml similarity index 75% rename from tests/integration/native-image/static-content/pom.xml rename to tests/integration/packaging/static-content/pom.xml index eb56878b61a..41fc6343022 100644 --- a/tests/integration/native-image/static-content/pom.xml +++ b/tests/integration/packaging/static-content/pom.xml @@ -20,14 +20,13 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - io.helidon.applications - helidon-se + io.helidon.tests.integration.packaging + helidon-tests-integration-packaging 4.1.0-SNAPSHOT - ../../../../applications/se/pom.xml + ../pom.xml - io.helidon.tests.integration - helidon-tests-native-image-static-content - Helidon Tests Integration GraalVM Native image Static Content + helidon-tests-integration-packaging-static-content + Helidon Tests Integration Packaging Static Content Static content jar file to use in other tests (to make sure we access a jar file and not a path). diff --git a/tests/integration/native-image/static-content/src/main/java/io/helidon/tests/integration/nativeimage/staticcontent/Dummy.java b/tests/integration/packaging/static-content/src/main/java/io/helidon/tests/integration/packaging/staticcontent/Dummy.java similarity index 84% rename from tests/integration/native-image/static-content/src/main/java/io/helidon/tests/integration/nativeimage/staticcontent/Dummy.java rename to tests/integration/packaging/static-content/src/main/java/io/helidon/tests/integration/packaging/staticcontent/Dummy.java index 5162557aa57..810a5a9d14b 100644 --- a/tests/integration/native-image/static-content/src/main/java/io/helidon/tests/integration/nativeimage/staticcontent/Dummy.java +++ b/tests/integration/packaging/static-content/src/main/java/io/helidon/tests/integration/packaging/staticcontent/Dummy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021 Oracle and/or its affiliates. + * Copyright (c) 2019, 2024 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.helidon.tests.integration.nativeimage.staticcontent; +package io.helidon.tests.integration.packaging.staticcontent; /** * This class exists so our jar file is correctly created. diff --git a/tests/integration/native-image/static-content/src/main/resources/web-jar/resource.txt b/tests/integration/packaging/static-content/src/main/resources/web-jar/resource.txt similarity index 100% rename from tests/integration/native-image/static-content/src/main/resources/web-jar/resource.txt rename to tests/integration/packaging/static-content/src/main/resources/web-jar/resource.txt diff --git a/tests/integration/pom.xml b/tests/integration/pom.xml index c2c8b772383..855fa6485d3 100644 --- a/tests/integration/pom.xml +++ b/tests/integration/pom.xml @@ -60,7 +60,6 @@ mp-graphql mp-security-client mp-ws-services - native-image oidc restclient restclient-connector @@ -88,4 +87,12 @@ + + + packaging + + packaging + + + From fbba2c2a964c21bbd5765a8053e881c5f2f2dbbc Mon Sep 17 00:00:00 2001 From: Romain Grecourt Date: Tue, 6 Aug 2024 17:29:19 -0700 Subject: [PATCH 36/37] DbClient IT tests job (#9107) - Exclude tests/integration/dbclient from the default reactor - Add a separate matrix job to execute the tests - Add a few IntelliJ suppressions in the top level pom.xml --- .github/workflows/validate.yml | 34 ++++++++++++++++++++++++++++++++-- pom.xml | 2 ++ tests/integration/pom.xml | 7 ++++++- 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index fbb9be5b363..c88f6c5f927 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -134,7 +134,7 @@ jobs: cache: maven - uses: graalvm/setup-graalvm@v1 with: - java-version: '21' + java-version: ${{ env.JAVA_VERSION }} distribution: graalvm-community github-token: ${{ secrets.GITHUB_TOKEN }} native-image-job-reports: true @@ -293,9 +293,39 @@ jobs: -Pnative-image \ -am \ verify + dbclient: + timeout-minutes: 60 + strategy: + matrix: + group: [ oracle, others ] + include: + - { group: others, modules: '!oracle' } + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v4 + - name: Set up JDK ${{ env.JAVA_VERSION }} + uses: actions/setup-java@v4.1.0 + with: + distribution: ${{ env.JAVA_DISTRO }} + java-version: ${{ env.JAVA_VERSION }} + cache: maven + - name: Build Helidon + run: | + # prime build + mvn ${MAVEN_ARGS} -e \ + -DskipTests \ + -Ptests \ + install + - name: Run Tests + run: | + mvn ${MAVEN_ARGS} -e \ + -f tests/integration/dbclient/pom.xml \ + -pl ${{ matrix.modules || matrix.group }} \ + -am \ + verify gate: runs-on: ubuntu-20.04 - needs: [ copyright, checkstyle, shellcheck, build, docs, spotbugs, packaging, native-image, archetypes, mp-tck ] + needs: [ copyright, checkstyle, shellcheck, build, docs, spotbugs, packaging, native-image, dbclient, archetypes, mp-tck ] steps: - shell: bash run: | diff --git a/pom.xml b/pom.xml index 8fb000087c2..8e211c55dd1 100644 --- a/pom.xml +++ b/pom.xml @@ -635,6 +635,7 @@ true 0 false + ${nvd-api-key} @@ -1319,6 +1320,7 @@ examples + helidon-examples diff --git a/tests/integration/pom.xml b/tests/integration/pom.xml index 855fa6485d3..502e1856d35 100644 --- a/tests/integration/pom.xml +++ b/tests/integration/pom.xml @@ -38,7 +38,6 @@ config - dbclient harness health jep290 @@ -88,6 +87,12 @@ + + dbclient + + dbclient + + packaging From a07579b7635f45d712066230e39b9727d8e86984 Mon Sep 17 00:00:00 2001 From: Romain Grecourt Date: Tue, 6 Aug 2024 18:52:25 -0700 Subject: [PATCH 37/37] Cleanup validate workflow (#9108) * Cleanup validate workflow. - Remove 'pipeline' Maven profile - Add -B -fae -e to MAVEN_ARGS - Remove usage of -Dmaven.test.skip=true (breaks tests jars) - Use -T for prime builds - Remove HELIDON_PIPELINES environment variable - Update example scripts to use https URL instead of SSH, use MAVEN_ARGS --- .github/workflows/validate.yml | 61 ++++++++++++++++----------------- etc/scripts/build-examples.sh | 5 +-- etc/scripts/test-quickstarts.sh | 2 +- metrics/metrics/pom.xml | 18 ---------- metrics/provider-tests/pom.xml | 23 ------------- microprofile/metrics/pom.xml | 19 ---------- 6 files changed, 33 insertions(+), 95 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index c88f6c5f927..d8c4c31993c 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -7,14 +7,15 @@ name: "Validate" on: pull_request: push: - branches-ignore: [ 'main', 'helidon-*.x' ] + branches-ignore: [ 'main', 'helidon-*.x', 'release-*' ] + tags-ignore: [ '**' ] workflow_call: env: JAVA_VERSION: '21' JAVA_DISTRO: 'oracle' - HELIDON_PIPELINES: 'true' MAVEN_ARGS: | + -B -fae -e -Dmaven.wagon.httpconnectionManager.ttlSeconds=60 -Dmaven.wagon.http.retryHandler.count=3 @@ -74,7 +75,7 @@ jobs: mvn ${MAVEN_ARGS} -e \ -DskipTests \ -Dmaven.test.skip=true \ - -Pspotbugs,pipeline \ + -Pspotbugs \ install docs: timeout-minutes: 30 @@ -89,12 +90,10 @@ jobs: cache: maven - name: Docs run: | - mvn ${MAVEN_ARGS} -e \ - -Dmaven.test.skip=true \ + mvn ${MAVEN_ARGS} \ -DskipTests \ - -Ppipeline \ install - mvn ${MAVEN_ARGS} -e \ + mvn ${MAVEN_ARGS} \ -f docs/pom.xml \ -Pjavadoc \ install @@ -114,9 +113,9 @@ jobs: cache: maven - name: Maven build run: | - mvn ${MAVEN_ARGS} -e \ + mvn ${MAVEN_ARGS} \ -Dmaven.test.failure.ignore=false \ - -Pjavadoc,sources,tests,pipeline \ + -Pjavadoc,sources,tests \ install examples: timeout-minutes: 40 @@ -142,29 +141,22 @@ jobs: - name: Maven build run: | # prime build - mvn ${MAVEN_ARGS} -e \ - -Dmaven.test.skip=true \ + mvn ${MAVEN_ARGS} -T8 \ -DskipTests \ - -Ppipeline \ install - - name: Examples checkout - uses: actions/checkout@v4 - with: - fetch-depth: '0' - repository: helidon-io/helidon-examples.git - ref: dev-4.x - path: helidon-examples - name: Examples build run: etc/scripts/build-examples.sh - name: Test quickstarts native image run: etc/scripts/test-quickstarts.sh mp-tck: timeout-minutes: 60 - name: "MicroProfile TCKs" strategy: matrix: os: [ ubuntu-20.04 ] + include: + - { os: ubuntu-20.04, platform: linux } runs-on: ${{ matrix.os }} + name: tests/tck-${{ matrix.platform }} steps: - uses: actions/checkout@v4 - name: Set up JDK ${{ env.JAVA_VERSION }} @@ -176,12 +168,10 @@ jobs: - name: Maven build run: | # prime build - mvn ${MAVEN_ARGS} -e \ - -Dmaven.test.skip=true \ + mvn ${MAVEN_ARGS} -T8 \ -DskipTests \ - -Ppipeline \ install - mvn ${MAVEN_ARGS} -e \ + mvn ${MAVEN_ARGS} \ -f microprofile/tests/tck/pom.xml \ -Ptck-ft \ verify @@ -202,10 +192,8 @@ jobs: - name: Test archetypes run: | # prime build - mvn ${MAVEN_ARGS} -e \ - -Dmaven.test.skip=true \ + mvn ${MAVEN_ARGS} -T8 \ -DskipTests \ - -Ppipeline \ install mvn ${MAVEN_ARGS} -e \ -f archetypes/pom.xml \ @@ -240,7 +228,7 @@ jobs: - name: Build Helidon run: | # prime build - mvn ${MAVEN_ARGS} -e \ + mvn ${MAVEN_ARGS} -T4 \ -DskipTests \ -Ptests \ install @@ -281,7 +269,7 @@ jobs: - name: Build Helidon run: | # prime build - mvn ${MAVEN_ARGS} -e \ + mvn ${MAVEN_ARGS} -T4 \ -DskipTests \ -Ptests \ install @@ -297,10 +285,13 @@ jobs: timeout-minutes: 60 strategy: matrix: + os: [ ubuntu-20.04 ] group: [ oracle, others ] include: - { group: others, modules: '!oracle' } - runs-on: ubuntu-20.04 + - { os: ubuntu-20.04, platform: linux } + runs-on: ${{ matrix.os }} + name: tests/dbclient-${{ matrix.group }}-${{ matrix.platform }} steps: - uses: actions/checkout@v4 - name: Set up JDK ${{ env.JAVA_VERSION }} @@ -309,16 +300,22 @@ jobs: distribution: ${{ env.JAVA_DISTRO }} java-version: ${{ env.JAVA_VERSION }} cache: maven + - name: Free Space + shell: bash + run: | + # See https://github.com/actions/runner-images/issues/2840 + sudo rm -rf /usr/share/dotnet + sudo rm -rf /usr/local/share/powershell - name: Build Helidon run: | # prime build - mvn ${MAVEN_ARGS} -e \ + mvn ${MAVEN_ARGS} -T4 \ -DskipTests \ -Ptests \ install - name: Run Tests run: | - mvn ${MAVEN_ARGS} -e \ + mvn ${MAVEN_ARGS} \ -f tests/integration/dbclient/pom.xml \ -pl ${{ matrix.modules || matrix.group }} \ -am \ diff --git a/etc/scripts/build-examples.sh b/etc/scripts/build-examples.sh index c4ffb2b352a..a9ac86b1a2a 100755 --- a/etc/scripts/build-examples.sh +++ b/etc/scripts/build-examples.sh @@ -47,11 +47,12 @@ readonly WS_DIR readonly HELIDON_EXAMPLES_PATH=${WS_DIR}/helidon-examples if [ ! -d "${WS_DIR}/helidon-examples" ]; then echo "Cloning examples repository into ${WS_DIR}/helidon-examples" - git clone --branch dev-4.x --single-branch git@github.com:helidon-io/helidon-examples.git "${WS_DIR}/helidon-examples" + git clone --branch dev-4.x --single-branch https://github.com/helidon-io/helidon-examples.git "${WS_DIR}/helidon-examples" fi version() { - mvn -B -N -f "${1}" -Dexpression=helidon.version help:evaluate | grep -v '\[INFO\]' + # shellcheck disable=SC2086 + mvn ${MAVEN_ARGS} -B -N -f "${1}" -Dexpression=helidon.version help:evaluate | grep -v '\[INFO\]' } # Make sure the helidon version from the example repo aligns with this repository diff --git a/etc/scripts/test-quickstarts.sh b/etc/scripts/test-quickstarts.sh index 174e48ad147..78c0b1b4313 100755 --- a/etc/scripts/test-quickstarts.sh +++ b/etc/scripts/test-quickstarts.sh @@ -58,7 +58,7 @@ mvn ${MAVEN_ARGS} --version # If needed we clone the helidon-examples repo into a subdirectory of the helidon repository if [ ! -d "${WS_DIR}/helidon-examples" ]; then echo "Cloning examples repository into ${HELIDON_EXAMPLES_PATH}" - git clone --branch dev-4.x --single-branch git@github.com:helidon-io/helidon-examples.git "${WS_DIR}/helidon-examples" + git clone --branch dev-4.x --single-branch https://github.com/helidon-io/helidon-examples.git "${WS_DIR}/helidon-examples" fi # Build quickstart native-image executable and run jar file diff --git a/metrics/metrics/pom.xml b/metrics/metrics/pom.xml index a293bd7ef92..adba141799b 100644 --- a/metrics/metrics/pom.xml +++ b/metrics/metrics/pom.xml @@ -148,23 +148,6 @@ - - pipeline - - - - org.apache.maven.plugins - maven-surefire-plugin - - - 45 - 0.25 - - - - - - release @@ -190,5 +173,4 @@ - diff --git a/metrics/provider-tests/pom.xml b/metrics/provider-tests/pom.xml index 08de79bb9e0..efb9dce4511 100644 --- a/metrics/provider-tests/pom.xml +++ b/metrics/provider-tests/pom.xml @@ -150,27 +150,4 @@ - - - - pipeline - - - - org.apache.maven.plugins - maven-surefire-plugin - - - 45 - 0.25 - - - - - - - - - - diff --git a/microprofile/metrics/pom.xml b/microprofile/metrics/pom.xml index 914cd6ade8a..8a629850243 100644 --- a/microprofile/metrics/pom.xml +++ b/microprofile/metrics/pom.xml @@ -213,23 +213,4 @@ - - - - pipeline - - - - org.apache.maven.plugins - maven-surefire-plugin - - - false - - - - - - -